include/HTMLRenderer/Mapper.hpp

Go to the documentation of this file.
00001 #ifndef hpp_CPP_Mapper_CPP_hpp
00002 #define hpp_CPP_Mapper_CPP_hpp
00003 
00004 // We need DOM declaration, as we will render a DOM
00005 #include "../HTMLParser/DOM.hpp"
00006 // We need container classes (to be confirmed if it is really needed)
00007 #include "../Containers/Container.hpp"
00008 // We need the box hierarchy model
00009 #include "BoxHierarchy.hpp"
00010 // We need allocators
00011 #include "Allocator.hpp"
00012 // We need table layout
00013 #include "TableLayout.hpp"
00014 
00015 namespace HTML
00016 {
00018     namespace Renderer
00019     {
00020         // Forward declare the box class
00021         class Box;
00022 
00028         struct RequiredRendererImplementation
00029         {
00030             // Font interface
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             // Helpers methods
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                 // Find the body element
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                     // @todo : Return the specified length to the allocator
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                     // Ignore comment children 
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; // Bad DOM tree
00386                     }
00387                 }
00388 
00389                 // Ignore comment sibling
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; // Bad DOM tree
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             // The allocator interface
00412         public:
00414             inline HTML::Renderer::Allocators::BaseAllocator & getHierarchyAllocator() { return boxHierarchyAllocator; }
00415 
00416             // Rendering interface
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             // Construction and destruction
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

(C) An X-Ryl669 project 2007

This document describes Unlimited Zooming Interface source code. UZI stands for Unlimited Zooming Interface, and source code license is