00001 #ifndef hpp_CPP_Mapper_CPP_hpp
00002 #define hpp_CPP_Mapper_CPP_hpp
00003
00004
00005 #include "../HTMLParser/DOM.hpp"
00006
00007 #include "../Containers/Container.hpp"
00008
00009 #include "BoxHierarchy.hpp"
00010
00011 #include "Allocator.hpp"
00012
00013 #include "TableLayout.hpp"
00014
00015 namespace HTML
00016 {
00018 namespace Renderer
00019 {
00020
00021 class Box;
00022
00028 struct RequiredRendererImplementation
00029 {
00030
00031 public:
00035 virtual CSS::Font * getDefaultFont() = 0;
00040 virtual CSS::Font * getBolderFont(CSS::Font * font) = 0;
00046 virtual CSS::Font * getScaledFont(CSS::Font * font, const float scale) = 0;
00052 virtual CSS::Font * getColouredFont(CSS::Font * font, const CSS::Colour & color) = 0;
00057 virtual CSS::Font * getItalicFont(CSS::Font * font) = 0;
00062 virtual CSS::Font * getMonospaceFont(CSS::Font * font) = 0;
00066 virtual uint32 getRenderedWidthOf(Box * box) = 0;
00070 virtual uint32 getRenderedHeightOf(Box * box) = 0;
00074 virtual uint32 getMinimumWidthOf(Box * box) = 0;
00078 virtual uint32 getMinimumHeightOf(Box * box) = 0;
00114 virtual bool getSplitLimitsOf(Box * box, const int32 boxLeft, const int32 boxRight, const int32 top, const int32 left, int32 & right, int32 & bottom) = 0;
00133 virtual TableLayout * getNewTableLayout(const BoxHierarchy * box) = 0;
00140 virtual TableLayout * getKnownTableLayout(const BoxHierarchy * box) = 0;
00175 virtual bool getMinAndMaxWidthOf(Box * box, int32 & minimumWidth, int32 & maximumWidth) = 0;
00176 };
00177
00185 class Mapper
00186 {
00187 private:
00189 Container::PlainOldData<Box *>::Array normalBoxes;
00191 Container::PlainOldData<Box *>::Array absoluteBoxes;
00193 Container::PlainOldData<Box *>::Array fixedBoxes;
00194
00195
00197 Box * containerBox;
00199 BoxHierarchy * rootBoxHierarchy;
00201 HTML::Renderer::Allocators::BaseAllocator & boxHierarchyAllocator;
00202
00204 uint32 viewportWidth;
00206 uint32 viewportHeight;
00208 RequiredRendererImplementation * rendererImpl;
00209
00211 const DOM::Node * root;
00213 const DOM::Element * bodyElement;
00214
00216 uint32 iteration;
00217
00218
00219 private:
00223 const DOM::Node * getNextNode(const DOM::Node * current) const
00224 {
00225 if (current->firstChild())
00226 {
00227 return current->firstChild();
00228 } else if (current->nextSibling())
00229 {
00230 return current->nextSibling();
00231 } else
00232 {
00233 while (current->parentNode() != root)
00234 {
00235 if (current->parentNode() && current->parentNode()->nextSibling())
00236 {
00237 current = current->parentNode()->nextSibling();
00238 return current;
00239 }
00240 current = current->parentNode();
00241 }
00242 return 0;
00243 }
00244 }
00245
00247 inline const DOM::Element * getBodyElement()
00248 {
00249 if (bodyElement) return bodyElement;
00250 if (!root || root->nodeType != DOM::Node::NodeType::Document) return 0;
00251
00252
00253 const DOM::Document * rootDocument = ((const DOM::Document *)root);
00254 DOM::NodeList * list = rootDocument->getElementsByTagName("BODY");
00255 if (!list || !list->length) { delete list; return 0; }
00256 const DOM::Node * node = list->item(0);
00257 delete list;
00258 if (!node || node->nodeType != DOM::Node::NodeType::Element) return 0;
00259 return bodyElement = (const DOM::Element*)node;
00260 }
00261
00263 inline bool clearBoxHierarchyList()
00264 {
00265 const BoxHierarchy * box = rootBoxHierarchy;
00266 while (box)
00267 {
00268 if (box->child) box = box->child;
00269 else if (box->next) box = box->next;
00270 else
00271 {
00272 const BoxHierarchy * toBeCleaned = box;
00273 if (box->previous) { box = box->previous; box->next = 0; }
00274 else { box = box->parent; if (box) box->child = 0; }
00275 boxHierarchyAllocator.returnBoxHierarchy(toBeCleaned);
00276 }
00277 }
00278
00279 rootBoxHierarchy = 0;
00280 return true;
00281 }
00282
00284 inline bool clearBoxList()
00285 {
00286 for (uint32 i = 0; i < normalBoxes.getSize(); i++)
00287 {
00288 Box * & current = normalBoxes[i];
00289 boxHierarchyAllocator.returnBox(current);
00290 }
00291
00292 normalBoxes.Clear();
00293 containerBox = 0;
00294 return true;
00295 }
00296
00298 inline bool filterElementNodes(const DOM::Node * node) const { return node && (node->nodeType == DOM::Node::NodeType::Element); }
00300 inline bool filterTextNodes(const DOM::Node * node) const { return node && (node->nodeType == DOM::Node::NodeType::Text); }
00301
00303 inline void clearStyleObject(CSS::StyleImplement & style) const
00304 {
00305 boxHierarchyAllocator.returnLength(style.contentHeight);
00306 boxHierarchyAllocator.returnLength(style.contentWidth);
00307 boxHierarchyAllocator.returnLength(style.borderTop);
00308 boxHierarchyAllocator.returnLength(style.borderLeft);
00309 boxHierarchyAllocator.returnLength(style.borderRight);
00310 boxHierarchyAllocator.returnLength(style.borderBottom);
00311 boxHierarchyAllocator.returnLength(style.marginTop);
00312 boxHierarchyAllocator.returnLength(style.marginLeft);
00313 boxHierarchyAllocator.returnLength(style.marginRight);
00314 boxHierarchyAllocator.returnLength(style.marginBottom);
00315 boxHierarchyAllocator.returnLength(style.paddingTop);
00316 boxHierarchyAllocator.returnLength(style.paddingLeft);
00317 boxHierarchyAllocator.returnLength(style.paddingRight);
00318 boxHierarchyAllocator.returnLength(style.paddingBottom);
00319 boxHierarchyAllocator.returnLength(style.positionTop);
00320 boxHierarchyAllocator.returnLength(style.positionLeft);
00321 boxHierarchyAllocator.returnLength(style.positionRight);
00322 boxHierarchyAllocator.returnLength(style.positionBottom);
00323
00324 boxHierarchyAllocator.returnLength(style.lineHeight.setNotOwnedLength(0));
00325 if (style.textAlign && style.textAlign->type == CSS::TextAlign::String)
00326 {
00327 delete (CSS::StringAlignedText*)style.textAlign;
00328 style.textAlign = 0;
00329 }
00330 if (style.verticalAlign && style.verticalAlign->type == CSS::VerticalAlign::Number)
00331 {
00332
00333 delete (CSS::SpecifiedVerticalAlign*)style.verticalAlign;
00334 style.verticalAlign = 0;
00335 }
00336 }
00337
00339 inline void implementBoxLinks(Box * box, Box * ancestor, Box * previous, bool & setNext, bool & setChild);
00341 const bool hasBlockLevelChildren(const BoxHierarchy * box) const;
00343 inline const bool isDisplayedAsBlock(const CSS::DisplayMode::Type displayType) const { return (displayType == CSS::DisplayMode::Block || displayType == CSS::DisplayMode::ListItem || displayType == CSS::DisplayMode::Compact || displayType == CSS::DisplayMode::RunIn || displayType == CSS::DisplayMode::Table); }
00344
00351 inline bool shouldCheckChildren(const DOM::Node * current) const;
00352
00353
00355 enum NextBoxType
00356 {
00357 DOMTreeError = (uint32)-1,
00358 NoNext = 0,
00359 TextChild = 1,
00360 ElementChild = 2,
00361 TextSibling = 3,
00362 ElementSibling = 4,
00363 ElementCSibling = 5,
00364 };
00370 inline NextBoxType nextBoxType(const BoxHierarchy * current, const DOM::Node *& last, bool seekChild = true) const
00371 {
00372 if (!current || !last) return DOMTreeError;
00373 const DOM::Node * currentElement = last;
00374 const DOM::Node * node = 0;
00375
00376 if (seekChild && shouldCheckChildren(currentElement) && currentElement->hasChildNodes())
00377 {
00378
00379 node = currentElement->firstChild();
00380 while (node && node->nodeType == DOM::Node::NodeType::Comment) node = node->nextSibling();
00381 if (node)
00382 {
00383 if (node->nodeType == DOM::Node::NodeType::Text) { last = node; return TextChild; }
00384 else if (node->nodeType == DOM::Node::NodeType::Element) { last = node; if (!current->child || current->child->element != node) return DOMTreeError; return ElementChild; }
00385 else if (node->nodeType != DOM::Node::NodeType::Comment) return DOMTreeError;
00386 }
00387 }
00388
00389
00390 node = currentElement->nextSibling();
00391 while (node && node->nodeType == DOM::Node::NodeType::Comment) node = node->nextSibling();
00392 if (node)
00393 {
00394 if (node->nodeType == DOM::Node::NodeType::Text) { last = node; return TextSibling; }
00395 else if (node->nodeType == DOM::Node::NodeType::Element) { last = node; if (current->child && current->child->element == node) return ElementCSibling; else if (!current->next || current->next->element != node) return DOMTreeError; return ElementSibling; }
00396 else if (node->nodeType != DOM::Node::NodeType::Comment) return DOMTreeError;
00397 }
00398 return NoNext;
00399 }
00400
00403 inline void iterateUp(const BoxHierarchy *& current, const DOM::Node *& last, Box *& ancestor, Box *& previous, Box *& box) const;
00405 inline bool createAndLinkTextBox(const DOM::Text * text, CSS::StyleImplement & style, const BoxHierarchy * current, Box *& ancestor, Box *& previous, Box *& box, bool & setChild, bool & setNext);
00407 inline bool createAndLinkElementBox(CSS::StyleImplement & style, const BoxHierarchy * current, Box *& ancestor, Box *& previous, Box *& box, bool & setChild, bool & setNext);
00409 inline bool createAndLinkAnonymousBox(CSS::StyleImplement & style, const BoxHierarchy * current, Box *& ancestor, Box *& previous, Box *& box, bool & setChild, bool & setNext);
00410
00411
00412 public:
00414 inline HTML::Renderer::Allocators::BaseAllocator & getHierarchyAllocator() { return boxHierarchyAllocator; }
00415
00416
00417 public:
00423 bool generateBoxes();
00424
00430 bool generateBoxHierarchy();
00431
00433 inline const BoxHierarchy * getRootHierarchy() const { return rootBoxHierarchy; }
00434
00436 inline Box * getViewportBox() { return containerBox; }
00438 inline const uint32 getViewportWidth() const { return viewportWidth; }
00440 inline const uint32 getViewportHeight() const { return viewportHeight; }
00441
00443 inline const uint32 getCurrentIteration() const { return iteration; }
00444
00446 inline uint32 getRenderedWidthOf(Box * box) const { return rendererImpl->getRenderedWidthOf(box); }
00448 inline uint32 getRenderedHeightOf(Box * box) const { return rendererImpl->getRenderedHeightOf(box); }
00450 inline uint32 getMinimumWidthOf(Box * box) const { return rendererImpl->getMinimumWidthOf(box); }
00452 inline uint32 getMinimumHeightOf(Box * box) const { return rendererImpl->getMinimumHeightOf(box); }
00454 inline uint32 getSplitLimitsOf(Box * box, const int32 boxLeft, const int32 boxRight, const int32 top, const int32 left, int32 & right, int32 & bottom) const { return rendererImpl->getSplitLimitsOf(box, boxLeft, boxRight, top, left, right, bottom); }
00456 inline bool getWidthsOf(Box * box, int32 & minWidth, int32 & maxWidth) const { return rendererImpl->getMinAndMaxWidthOf(box, minWidth, maxWidth); }
00458 inline CSS::Font * getDefaultFont() const { return rendererImpl->getDefaultFont(); }
00460 inline CSS::Font * getBolderFont(CSS::Font * font) const { return rendererImpl->getBolderFont(font); }
00462 inline CSS::Font * getScaledFont(CSS::Font * font, const float scale) const { return rendererImpl->getScaledFont(font, scale); }
00464 inline CSS::Font * getItalicFont(CSS::Font * font) const { return rendererImpl->getItalicFont(font); }
00466 inline CSS::Font * getMonospaceFont(CSS::Font * font) const { return rendererImpl->getMonospaceFont(font); }
00468 inline CSS::Font * getColouredFont(CSS::Font * font, const CSS::Colour & color) const { return rendererImpl->getColouredFont(font, color); }
00469
00472 const int32 getFloatLeft(Box * container) const { return 0; }
00475 const int32 getFloatRight(Box * container) const { return 0; }
00478 const int32 getFloatBottom(Box * container) const { return 0; }
00481 const bool areFloatBoxInContainer(Box * container) const { return false; }
00482
00484 const bool hasBlockLevelChildren(const Box * box) const;
00486 const uint32 findTopChildrenPos(Box * box, bool blockLevelOnly = true, bool setIteration = true) const;
00488 const uint32 findBottomChildrenPos(Box * box, bool blockLevelOnly = true, bool setIteration = true) const;
00490 const uint32 findLeftChildrenPos(Box * box, bool blockLevelOnly = true) const;
00492 const uint32 findRightChildrenPos(Box * box, bool blockLevelOnly = true) const;
00496 const bool shouldBeSeenAsBlock(Box * box) const;
00498 inline bool isFormBasedElement(const BoxHierarchy * box) const { return !shouldCheckChildren(box->element); }
00500 inline bool isLinkElement(const BoxHierarchy * box) const { return box->isTaggedAs(GenericElement::A); }
00501
00505 bool getStyleFor(const BoxHierarchy * box, CSS::StyleImplement & style) const;
00509 CSS::DisplayMode::Type getDisplayStyleFor(const BoxHierarchy * box) const;
00510
00512 inline Box * getRenderedBox(const uint32 index) { return normalBoxes[index]; }
00514 void resizedTo(const uint32 width, const uint32 height);
00515
00517 TableLayout * getTableLayout(Box * box) const;
00518
00519
00520
00521
00522 public:
00533 Mapper(const DOM::Node * _root, HTML::Renderer::Allocators::BaseAllocator & allocator, const uint32 viewWidth, const uint32 viewHeight, RequiredRendererImplementation * ri)
00534 : root(_root), bodyElement(0), boxHierarchyAllocator(allocator), viewportWidth(viewWidth), viewportHeight(viewHeight), rootBoxHierarchy(0), containerBox(0), rendererImpl(ri), iteration(0) {}
00535
00537 ~Mapper();
00538 };
00539 }
00540 }
00541
00542 #endif