00001 #ifndef hpp_CPP_GenericRenderer_CPP_hpp
00002 #define hpp_CPP_GenericRenderer_CPP_hpp
00003
00004
00005 #include "../CSS/CSSUnit.hpp"
00006
00007 #include "Mapper.hpp"
00008
00009 namespace HTML
00010 {
00012 namespace Renderer
00013 {
00027 class Box
00028 {
00029
00030 public:
00032 typedef CSS::Length Length;
00034 typedef CSS::Colour Colour;
00036 typedef CSS::LineHeight LineHeight;
00038 typedef CSS::Font Font;
00040 typedef CSS::DisplayMode::Type DisplayMode;
00042 typedef CSS::TextAlign TextAlign;
00044 typedef CSS::VerticalAlign VerticalAlign;
00046 typedef CSS::TextDecoration::Type TextDecoration;
00047
00048
00049
00050 private:
00055 struct Content
00056 {
00058 Length * width;
00060 Length * height;
00061
00063 Content(Length * _width = 0, Length * _height = 0) : width(_width), height(_height) {}
00065 ~Content() { }
00066
00068 inline uint32 getWidth(const uint32 iteration) const { if (width) return (uint32)width->getAsPixels(iteration); return 0; }
00070 inline uint32 getHeight(const uint32 iteration) const { if (height) return (uint32)height->getAsPixels(iteration); return 0; }
00071
00073 inline void setComputedWidth(const uint32 newWidth, const uint32 iteration) const { if (width) width->setComputedValue(newWidth, iteration); }
00075 inline void setComputedHeight(const uint32 newHeight, const uint32 iteration) const { if (height) height->setComputedValue(newHeight, iteration); }
00076 };
00077
00083 struct Rectangle
00084 {
00086 Length * top;
00088 Length * bottom;
00090 Length * left;
00092 Length * right;
00093
00095 Rectangle(Length * _top = 0, Length * _left = 0, Length * _right = 0, Length * _bottom = 0) : top(_top), bottom(_bottom), left(_left), right(_right) {}
00097 ~Rectangle() { }
00098
00100 inline int32 getWidth(const uint32 iteration) const { return (left ? left->getAsPixels(iteration) : 0) + (right ? right->getAsPixels(iteration) : 0); }
00102 inline int32 getLeftWidth(const uint32 iteration) const { return (left ? left->getAsPixels(iteration) : 0); }
00104 inline int32 getRightWidth(const uint32 iteration) const { return (right ? right->getAsPixels(iteration) : 0); }
00106 inline int32 getHeight(const uint32 iteration) const { return (top ? top->getAsPixels(iteration) : 0) + (bottom ? bottom->getAsPixels(iteration) : 0);}
00108 inline int32 getTopWidth(const uint32 iteration) const { return (top ? top->getAsPixels(iteration) : 0); }
00110 inline int32 getBottomWidth(const uint32 iteration) const { return (bottom ? bottom->getAsPixels(iteration) : 0); }
00111
00113 inline void setLeftWidth(const int32 width, const uint32 iteration) const { if (left) left->setComputedValue(width, iteration); }
00115 inline void setRightWidth(const int32 width, const uint32 iteration) const { if (right) right->setComputedValue(width, iteration); }
00116
00118 inline void setTopHeight(const int32 height, const uint32 iteration) const { if (top) top->setComputedValue(height, iteration); }
00120 inline void setBottomHeight(const int32 height, const uint32 iteration) const { if (bottom) bottom->setComputedValue(height, iteration); }
00121 };
00122
00124 typedef Rectangle Padding;
00126 typedef Rectangle Margin;
00127
00129 struct Border
00130 {
00135 struct Side
00136 {
00138 typedef CSS::BorderStyle::Style BorderStyle;
00139
00140
00141 private:
00143 Length * length;
00145 BorderStyle style;
00147 Colour color;
00148
00149 public:
00151 Side(Length * len = 0, const BorderStyle _style = CSS::BorderStyle::None, const Colour & colour = CSS::Colours::Black) : length(len), style(_style), color(colour) { checkLength(); }
00153 ~Side() { }
00154
00156 inline void setStyle(const BorderStyle _style) { style = _style; checkLength(); }
00158 inline void checkLength() { if (length && (style == CSS::BorderStyle::None || style == CSS::BorderStyle::Hidden)) length->setZero(); }
00160 inline int32 getAsPixels(const uint32 iteration) const { if (length) return length->getAsPixels(iteration); return 0; }
00162 inline BorderStyle getStyle() const { return style; }
00164 inline bool isVisible() const { return style != CSS::BorderStyle::None && style != CSS::BorderStyle::Hidden; }
00166 inline bool isAuto() const { return (length ? length->isAuto() : false); }
00168 inline const Colour & getColour() const { return color; }
00169
00171 inline void setValue(const int32 value, const uint32 iteration) const { if (length && style != CSS::BorderStyle::None && style != CSS::BorderStyle::Hidden) length->setComputedValue(value, iteration); }
00172
00173 friend class HTML::Renderer::Box;
00174 };
00175
00176
00178 Side top;
00180 Side bottom;
00182 Side left;
00184 Side right;
00185
00187 Border(Length * _top = 0, const Side::BorderStyle topStyle = CSS::BorderStyle::None, const Colour & topColor = CSS::Colours::Black,
00188 Length * _left = 0, const Side::BorderStyle leftStyle = CSS::BorderStyle::None, const Colour & leftColor = CSS::Colours::Black,
00189 Length * _right = 0, const Side::BorderStyle rightStyle = CSS::BorderStyle::None, const Colour & rightColor = CSS::Colours::Black,
00190 Length * _bottom = 0, const Side::BorderStyle bottomStyle = CSS::BorderStyle::None, const Colour & bottomColor = CSS::Colours::Black)
00191 : top(_top, topStyle, topColor), bottom(_bottom, bottomStyle, bottomColor),
00192 left(_left, leftStyle, leftColor), right(_right, rightStyle, rightColor) {}
00193
00195 inline int32 getWidth(const uint32 iteration) const { return left.getAsPixels(iteration) + right.getAsPixels(iteration); }
00197 inline int32 getLeftWidth(const uint32 iteration) const { return left.getAsPixels(iteration); }
00199 inline int32 getRightWidth(const uint32 iteration) const { return right.getAsPixels(iteration); }
00201 inline int32 getHeight(const uint32 iteration) const { return top.getAsPixels(iteration) + bottom.getAsPixels(iteration);}
00203 inline int32 getTopWidth(const uint32 iteration) const { return top.getAsPixels(iteration); }
00205 inline int32 getBottomWidth(const uint32 iteration) const { return bottom.getAsPixels(iteration); }
00206
00208 inline void setLeftWidth(const int32 width, const uint32 iteration) const { left.setValue(width, iteration); }
00210 inline void setRightWidth(const int32 width, const uint32 iteration) const { right.setValue(width, iteration); }
00212 inline void setTopHeight(const int32 height, const uint32 iteration) const { top.setValue(height, iteration); }
00214 inline void setBottomHeight(const int32 height, const uint32 iteration) const { bottom.setValue(height, iteration); }
00215 };
00216
00218 struct BoxSizes
00219 {
00221 Content content;
00223 Padding padding;
00225 Border border;
00227 Margin margin;
00228
00230 BoxSizes( Length * width = 0, Length * height = 0,
00231 Length * paddingTop = 0, Length * paddingLeft = 0, Length * paddingRight = 0, Length * paddingBottom = 0,
00232 Length * marginTop = 0, Length * marginLeft = 0, Length * marginRight = 0, Length * marginBottom = 0,
00233 Length * borderTop = 0, const CSS::BorderStyle::Style topStyle = CSS::BorderStyle::None, const Colour & topColor = CSS::Colours::Black,
00234 Length * borderLeft = 0, const CSS::BorderStyle::Style leftStyle = CSS::BorderStyle::None, const Colour & leftColor = CSS::Colours::Black,
00235 Length * borderRight = 0, const CSS::BorderStyle::Style rightStyle = CSS::BorderStyle::None, const Colour & rightColor = CSS::Colours::Black,
00236 Length * borderBottom = 0, const CSS::BorderStyle::Style bottomStyle = CSS::BorderStyle::None, const Colour & bottomColor = CSS::Colours::Black)
00237 : content(width, height),
00238 padding(paddingTop, paddingLeft, paddingRight, paddingBottom),
00239 margin(marginTop, marginLeft, marginRight, marginBottom),
00240 border(borderTop, topStyle, topColor,
00241 borderLeft, leftStyle, leftColor,
00242 borderRight, rightStyle, rightColor,
00243 borderBottom, bottomStyle, bottomColor) { }
00244 };
00245
00250 struct Position
00251 {
00253 typedef CSS::Position::Type Type;
00255 Type type;
00257 Length * top;
00259 Length * bottom;
00261 Length * left;
00263 Length * right;
00264
00266 inline bool absolutelyPositioned() const { return type == CSS::Position::Absolute || type == CSS::Position::Fixed; }
00267
00269 inline int32 getLeft(const uint32 iteration) const { return left ? left->getAsPixels(iteration) : 0; }
00271 inline int32 getRight(const uint32 iteration) const { return right ? right->getAsPixels(iteration) : 0; }
00273 inline int32 getTop(const uint32 iteration) const { return top ? top->getAsPixels(iteration) : 0; }
00275 inline int32 getBottom(const uint32 iteration) const { return bottom ? bottom->getAsPixels(iteration) : 0; }
00276
00278 inline void setLeft(const int32 width, const uint32 iteration) const { if (left) left->setComputedValue(width, iteration); }
00280 inline void setRight(const int32 width, const uint32 iteration) const { if (right) right->setComputedValue(width, iteration); }
00282 inline void setTop(const int32 height, const uint32 iteration) const { if (top) top->setComputedValue(height, iteration); }
00284 inline void setBottom(const int32 height, const uint32 iteration) const { if (bottom) bottom->setComputedValue(height, iteration); }
00285
00287 Position(const Type & _type = CSS::Position::Static, Length * _top = 0, Length * _left = 0, Length * _right = 0, Length * _bottom = 0) : type(_type), top(_top), bottom(_bottom), left(_left), right(_right) {}
00290 ~Position() { delete top; delete bottom; delete left; delete right; }
00291 };
00292
00294 struct ComputedPosition
00295 {
00297 int32 top;
00299 int32 bottom;
00301 int32 left;
00303 int32 right;
00304
00306 inline void Reset() { top = bottom = left = right = 0; }
00309 inline int32 getWidth() const { return left + right; }
00312 inline int32 getHeight() const { return top + bottom;}
00316 inline int32 getTrueWidth() const { return left + (right > 0 ? right : 0); }
00320 inline int32 getTrueHeight() const { return top + (bottom > 0 ? bottom : 0);}
00321
00323 ComputedPosition() : top(0), bottom(0), left(0), right(0) {}
00324 };
00325
00327 struct ComputedContent
00328 {
00330 uint32 width;
00332 uint32 height;
00333
00335 inline uint32 getWidth() const { return width; }
00337 inline uint32 getHeight() const { return height; }
00338
00340 inline void Reset() { width = height = 0; }
00341 };
00342
00344 struct ComputedBoxSizes
00345 {
00347 ComputedContent content;
00349 ComputedPosition padding;
00351 ComputedPosition border;
00353 ComputedPosition margin;
00354
00356 inline void Reset() { content.Reset(); padding.Reset(); border.Reset(); margin.Reset(); }
00357 };
00358
00360 struct ClearAndFloat
00361 {
00363 typedef CSS::ClearAndFloat::Property Property;
00364
00366 Property floating;
00368 Property clearing;
00369
00371 inline const Property getFloat() const { return floating; }
00373 inline const Property getClear() const { return clearing; }
00374
00376 inline bool isClearFromLeft() const { return clearing == CSS::ClearAndFloat::Left || clearing == CSS::ClearAndFloat::Both; }
00378 inline bool isClearFromRight() const { return clearing == CSS::ClearAndFloat::Right || clearing == CSS::ClearAndFloat::Both; }
00379
00381 inline void setFloat(const Property floatProp) { floating = floatProp; if (floating == CSS::ClearAndFloat::Both) floating = CSS::ClearAndFloat::None; }
00383 inline void setClear(const Property clearProp) { clearing = clearProp; }
00384
00386 ClearAndFloat(const Property floatProp = CSS::ClearAndFloat::None, const Property clearProp = CSS::ClearAndFloat::None) : floating(floatProp), clearing(clearProp) {}
00387 };
00388
00390 struct SplitLimit
00391 {
00393 int32 right;
00395 int32 left;
00396
00398 SplitLimit(const int32 _left = 0, const int32 _right = 0) : left(_left), right(_right) {}
00400 inline void Reset() { right = left = 0; }
00401 };
00402
00403
00405 const BoxSizes declaredBox;
00407 const Position declaredPos;
00408 public:
00410 enum ContentType
00411 {
00412 Text = 0,
00413 Image = 1,
00414 Object = 2,
00415 Input = 3,
00416 TextArea = 4,
00417 Select = 5,
00418 Button = 6,
00419 Table = 7,
00420 Other = 8,
00421 } contentType;
00423 Strings::FastString contentText;
00425 ComputedBoxSizes computedBox;
00427 ComputedPosition computedPos;
00429 DisplayMode displayMode;
00431 SplitLimit splitLimit;
00432
00434 bool leftToRight;
00436 LineHeight lineHeight;
00438 Font * boxFont;
00440 ClearAndFloat clearAndFloat;
00442 TextAlign * textAlign;
00444 VerticalAlign * verticalAlign;
00446 TextDecoration textDecoration;
00447
00449 const BoxHierarchy *UID;
00451 Mapper & mapper;
00452
00454 Box * ancestor;
00456 Box * container;
00458 Box * previous;
00460 Box * next;
00462 Box * child;
00463
00465 uint32 iteration;
00466
00468 inline Box * findFirstChildOf(Box * container) { return container->child; }
00470 inline Box * findLastChildOf(Box * container) { Box * child = container->child; while (child && child->next) child = child->next; return child; }
00471
00473 bool renderAsAnonymousBlock;
00474
00475
00478 void findContainingBlock()
00479 {
00480
00481 if (!declaredPos.absolutelyPositioned())
00482 container = ancestor;
00483 else if (declaredPos.type == CSS::Position::Fixed)
00484 container = mapper.getViewportBox();
00485 else if (declaredPos.type == CSS::Position::Absolute)
00486 {
00487 Box * ancest = ancestor;
00488 while (ancest)
00489 {
00490 if (ancest->declaredPos.type != CSS::Position::Static) break;
00491 ancest = ancest->ancestor;
00492 }
00493
00494
00495 container = ancest;
00496 }
00497 }
00498
00500 void findFirstBlockContainer()
00501 {
00502
00503 Box * ancest = container;
00504 while (ancest)
00505 {
00506 if (ancest->displayedAsBlock()) break;
00507 ancest = ancest->ancestor;
00508 }
00509
00510 if (ancest)
00511 {
00512 ComputedPosition boxSize;
00513 ancest->getContentPosition(boxSize);
00514 splitLimit.left = boxSize.left; splitLimit.right = boxSize.right;
00515 }
00516 }
00517
00519 inline uint32 max(const uint32 a, const uint32 b) const { return a > b ? a : b; }
00520
00536 bool computeRenderingSize(const uint32 currentIteration, const uint32 top = 0)
00537 {
00538
00539 if (currentIteration <= iteration) return true;
00540 computedPos.Reset(); computedBox.Reset(); splitLimit.Reset();
00541
00542
00543 findContainingBlock();
00544
00545 ComputedPosition boxSize;
00546
00547 if (!container)
00548 {
00549 boxSize.right = mapper.getViewportWidth();
00550 boxSize.bottom = mapper.getViewportHeight();
00551 } else
00552 {
00553 container->getContentPosition(boxSize);
00554 if (declaredPos.type == CSS::Position::Absolute)
00555 {
00556 if (container->displayedAsBlock())
00557 {
00558 boxSize.top -= computedBox.padding.top;
00559 boxSize.left -= computedBox.padding.left;
00560 boxSize.right += computedBox.padding.right;
00561 boxSize.bottom += computedBox.padding.bottom;
00562 } else
00563 {
00564 ComputedPosition firstBox, lastBox;
00565 Box * first = findFirstChildOf(container);
00566 Box * last = findLastChildOf(container);
00567 if (first && last)
00568 {
00569 first->getContentPosition(firstBox);
00570 last->getContentPosition(lastBox);
00571 if (container->leftToRight)
00572 {
00573 boxSize.top = firstBox.top;
00574 boxSize.left = firstBox.left;
00575 boxSize.right = lastBox.right;
00576 boxSize.bottom = lastBox.bottom;
00577 } else
00578 {
00579 boxSize.top = firstBox.top;
00580 boxSize.right = firstBox.right;
00581 boxSize.left = lastBox.left;
00582 boxSize.bottom = lastBox.bottom;
00583 }
00584 }
00585 }
00586 }
00587 }
00588
00589
00590 if (displayMode == CSS::DisplayMode::None) { computedPos = boxSize; computedPos.right = boxSize.left; computedPos.bottom = boxSize.top; iteration = currentIteration; return true; }
00591
00592
00593
00594 bool isBlock = displayedAsBlock() || isFloating();
00595
00596
00597 if (isFloating())
00598 {
00599
00600 zeroIfAuto(declaredPos.left);
00601 zeroIfAuto(declaredPos.right);
00602 zeroIfAuto(declaredBox.margin.left);
00603 zeroIfAuto(declaredBox.margin.right);
00604 uint32 width = (declaredBox.content.width && !declaredBox.content.width->isAuto()) ? declaredBox.content.getWidth(currentIteration) : (replacedElement() ? getReplacedWidth() : mapper.getRenderedWidthOf(this));
00605
00606
00607 zeroIfAuto(declaredPos.top);
00608 zeroIfAuto(declaredPos.bottom);
00609 zeroIfAuto(declaredBox.margin.top);
00610 zeroIfAuto(declaredBox.margin.bottom);
00611 uint32 height = (declaredBox.content.height && !declaredBox.content.height->isAuto()) ? declaredBox.content.getHeight(currentIteration) : (replacedElement() ? getReplacedHeight() : mapper.getRenderedHeightOf(this));
00612
00613 computedPos.top = boxSize.top;
00614 computedPos.bottom = boxSize.top + height + declaredBox.padding.getHeight(currentIteration) + declaredBox.border.getHeight(currentIteration) + declaredBox.margin.getHeight(currentIteration);
00615
00616 if (clearAndFloat.getFloat() == CSS::ClearAndFloat::Left)
00617 {
00618
00619 computedPos.left = mapper.getFloatLeft(container);
00620 computedPos.right = boxSize.left + width + declaredBox.padding.getWidth(currentIteration) + declaredBox.border.getWidth(currentIteration) + declaredBox.margin.getWidth(currentIteration);
00621 } else
00622 {
00623
00624 computedPos.right = mapper.getFloatRight(container);
00625 computedPos.left = boxSize.right - (width + declaredBox.padding.getWidth(currentIteration) + declaredBox.border.getWidth(currentIteration) + declaredBox.margin.getWidth(currentIteration));
00626 }
00627
00628 transferDeclaredValues(false);
00629 computedBox.content.width = width;
00630 computedBox.content.height = height;
00631 setComputedValues();
00632 } else
00633 {
00634
00635 bool shouldBeSeenAsBlock = mapper.shouldBeSeenAsBlock(this);
00636 if (!isBlock && !replacedElement() && shouldBeSeenAsBlock)
00637 {
00638 displayMode = CSS::DisplayMode::Block;
00639 isBlock = true;
00640 }
00641
00642 Box * previousBox = previous;
00643
00644
00645
00646
00647 if (isBlock )
00648 {
00649
00650
00651 while (previousBox && previousBox->displayMode == CSS::DisplayMode::None) previousBox = previousBox->previous;
00652
00653 if (previousBox && previousBox->displayedAsBlock())
00654 {
00655
00656
00657
00658 uint32 topMargin = max(previousBox->computedBox.margin.bottom, (declaredBox.margin.top && !declaredBox.margin.top->isAuto()) ? declaredBox.margin.getTopWidth(currentIteration) : 0);
00659 computedPos.top = previousBox->computedPos.bottom - previousBox->computedBox.margin.bottom + topMargin;
00660 computedPos.left = boxSize.left;
00661 computedPos.right = boxSize.right;
00662 computedPos.bottom = boxSize.bottom;
00663 } else if (previousBox)
00664 {
00665
00666
00667
00668
00669 computedPos.left = boxSize.left; computedPos.right = boxSize.right;
00670 computedPos.top = previousBox->computedPos.bottom;
00671 computedPos.bottom = boxSize.bottom;
00672 } else
00673 {
00674 computedPos.top = boxSize.top;
00675 computedPos.left = boxSize.left;
00676 computedPos.right = boxSize.right;
00677 computedPos.bottom = boxSize.bottom;
00678 }
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 } else
00694 {
00695 if (!mapper.areFloatBoxInContainer(container))
00696 {
00697
00698
00699 if (previousBox)
00700 {
00701
00702 if (previousBox->displayedAsBlock())
00703 {
00704 computedPos.top = previousBox->computedPos.bottom;
00705 computedPos.left = boxSize.left;
00706 } else
00707 {
00708 computedPos.top = previousBox->computedPos.bottom
00709 - previousBox->computedBox.padding.bottom
00710 - previousBox->computedBox.border.bottom
00711 - previousBox->computedBox.margin.bottom
00712 - (previousBox->replacedElement() ? previousBox->computedBox.content.getHeight() : previousBox->lineHeight.getHeightInPixels(previousBox->boxFont, currentIteration));
00713 computedPos.left = previousBox->computedPos.right;
00714 }
00715 } else
00716 {
00717 computedPos.top = boxSize.top;
00718 computedPos.left = boxSize.left;
00719 }
00720 computedPos.right = boxSize.right;
00721 computedPos.bottom = boxSize.bottom;
00722
00723 } else
00724 {
00725 computedPos.right = boxSize.right;
00726 computedPos.bottom = boxSize.bottom;
00727
00728 bool shiftDown = false;
00729 if (!clearAndFloat.isClearFromLeft()) computedPos.left = mapper.getFloatLeft(container);
00730 else shiftDown = true;
00731 if (!clearAndFloat.isClearFromRight()) computedPos.right = mapper.getFloatRight(container);
00732 else shiftDown = true;
00733 if (shiftDown) computedPos.top = mapper.getFloatBottom(container);
00734 else
00735 {
00736
00737
00738 if (previous)
00739 {
00740
00741 computedPos.top = previousBox->computedPos.bottom - previousBox->computedBox.padding.bottom - previousBox->computedBox.border.bottom - previousBox->computedBox.margin.bottom - previousBox->lineHeight.getHeightInPixels(previousBox->boxFont, currentIteration);;
00742 computedPos.left = previousBox->computedPos.right;
00743 } else
00744 {
00745 computedPos.top = boxSize.top;
00746 computedPos.left = boxSize.left;
00747 }
00748 }
00749 }
00750 }
00751
00752
00753
00754 uint32 width = computedPos.right - computedPos.left;
00755 uint32 height = computedPos.bottom - computedPos.top;
00756
00757
00758 if (contentType == Table)
00759 {
00760
00761
00762 TableLayout * tableLayout = mapper.getTableLayout(this);
00763 if (tableLayout)
00764 {
00765
00766 int32 previousMaxWidth = 0;
00767 computeTableWidths(0, previousMaxWidth);
00768
00769 zeroIfAuto(declaredPos.left);
00770 zeroIfAuto(declaredPos.right);
00771
00772
00773 solveBlockLevelWidth(boxSize.right - boxSize.left);
00774
00775 zeroIfAuto(declaredPos.top);
00776 zeroIfAuto(declaredPos.bottom);
00777 zeroIfAuto(declaredBox.margin.top);
00778 zeroIfAuto(declaredBox.margin.bottom);
00779
00780 transferDeclaredValues(false);
00781
00782 uint32 bottom = 0;
00783
00784
00785 if (tableLayout->minimumWidth > width)
00786 {
00787
00789
00790 assignWidthToTable(0, tableLayout, currentIteration, width, bottom);
00791 } else if (tableLayout->maximumWidth <= width)
00792 {
00793 assignWidthToTable(1, tableLayout, currentIteration, width, bottom);
00794 } else
00795 {
00796 assignWidthToTable(2, tableLayout, currentIteration, width, bottom);
00797 }
00798
00799 declaredBox.content.width->setComputedValue(width, currentIteration);
00800 declaredBox.content.height->setComputedValue(bottom - computedPos.top, currentIteration);
00801 computedBox.content.height = bottom - computedPos.top;
00802 computedBox.content.width = width;
00803
00804
00805 computedPos.right = computedPos.left + getBlockWidth();
00806 computedPos.bottom = computedPos.top + getBlockHeight();
00807 }
00808 else
00809 {
00810
00811 return false;
00812 }
00813
00814 iteration = currentIteration;
00815 return true;
00816 }
00817
00818 if (!isBlock)
00819 {
00820
00821 zeroIfAuto(declaredPos.left);
00822 zeroIfAuto(declaredPos.right);
00823 zeroIfAuto(declaredBox.margin.left);
00824 zeroIfAuto(declaredBox.margin.right);
00825
00826 zeroIfAuto(declaredPos.top);
00827 zeroIfAuto(declaredPos.bottom);
00828 zeroIfAuto(declaredBox.margin.top);
00829 zeroIfAuto(declaredBox.margin.bottom);
00830
00831
00832 transferDeclaredValues(false);
00833
00834 if (replacedElement())
00835 {
00836 if (declaredBox.content.width) computedBox.content.width = declaredBox.content.width->isAuto() ? getReplacedWidth() : declaredBox.content.width->getAsPixels(currentIteration);
00837 else computedBox.content.width = mapper.getMinimumWidthOf(this);
00838
00839
00840 if (declaredBox.content.height) computedBox.content.height = declaredBox.content.height->isAuto() ? getReplacedHeight() : declaredBox.content.height->getAsPixels(currentIteration);
00841 else computedBox.content.height = mapper.getMinimumHeightOf(this);
00842 } else
00843 {
00844
00845 if (child)
00846 {
00847
00848 uint32 top, bottom, left, right;
00849
00850 top = mapper.findTopChildrenPos(this, false);
00851 bottom = mapper.findBottomChildrenPos(this, false);
00852 left = mapper.findLeftChildrenPos(this, false);
00853 right = mapper.findRightChildrenPos(this, false);
00854
00855
00856 if (declaredBox.content.height) declaredBox.content.height->setComputedValue(bottom - top, currentIteration);
00857 computedBox.content.height = bottom - top;
00858 if (declaredBox.content.width) declaredBox.content.width->setComputedValue(right - left, currentIteration);
00859 computedBox.content.width = right - left;
00860 } else
00861 {
00862
00863 computedBox.content.height = lineHeight.getHeightInPixels(boxFont, currentIteration);
00864 lineHeight.setComputedValue(computedBox.content.height, currentIteration);
00865
00866
00867
00868
00869
00870 uint32 minWidth = mapper.getMinimumWidthOf(this);
00871
00872 if (minWidth + ((uint32)(declaredBox.border.getWidth(currentIteration) + declaredBox.margin.getWidth(currentIteration) + declaredBox.padding.getWidth(currentIteration)))> (uint32)(boxSize.right - computedPos.left))
00873 {
00874
00875 computedBox.content.width = boxSize.right - boxSize.left;
00876 setComputedValues();
00877
00878 splitLimit.right = boxSize.right; splitLimit.left = boxSize.left;
00879
00880
00881
00882 findFirstBlockContainer();
00883 mapper.getSplitLimitsOf(this, splitLimit.left, splitLimit.right, computedPos.top, computedPos.left, computedPos.right, computedPos.bottom);
00884 computedBox.content.height = computedPos.bottom - computedPos.top;
00885
00886
00887 iteration = currentIteration;
00888 return true;
00889 }
00890 {
00891 computedBox.content.width = minWidth;
00892 }
00893 }
00894
00895 }
00896
00897 setComputedValues();
00898 computedPos.right = computedPos.left + getBlockWidth();
00899 computedPos.bottom = computedPos.top + getBlockHeight();
00900 } else if (isBlock)
00901 {
00902 if (!declaredPos.absolutelyPositioned())
00903 {
00904
00905 zeroIfAuto(declaredPos.left);
00906 zeroIfAuto(declaredPos.right);
00907
00908
00909 solveBlockLevelWidth(boxSize.right - boxSize.left);
00910
00911
00912 zeroIfAuto(declaredPos.top);
00913 zeroIfAuto(declaredPos.bottom);
00914 zeroIfAuto(declaredBox.margin.top);
00915 zeroIfAuto(declaredBox.margin.bottom);
00916
00917 transferDeclaredValues(false);
00918
00919 if (declaredBox.content.height && declaredBox.content.height->isAuto())
00920 {
00921 uint32 top = 0, bottom = 0;
00922 if (replacedElement())
00923 {
00924
00925 bottom = getReplacedHeight();
00926 } else
00927 {
00928
00929 if (mapper.hasBlockLevelChildren(this))
00930 {
00931
00932 top = computedPos.top;
00933 bottom = mapper.findBottomChildrenPos(this, true);
00934 } else
00935 {
00936 top = mapper.findTopChildrenPos(this, false);
00937 bottom = mapper.findBottomChildrenPos(this, false);
00938 }
00939 }
00940 declaredBox.content.height->setComputedValue(bottom - top, currentIteration);
00941 computedBox.content.height = bottom - top;
00942 } else
00943 {
00944 computedBox.content.height = declaredBox.content.height ? declaredBox.content.height->getAsPixels(currentIteration) : 0;
00945 }
00946
00947
00948 computedPos.right = computedPos.left + getBlockWidth();
00949 computedPos.bottom = computedPos.top + getBlockHeight();
00950 } else
00951 solveAbsoluteBlockLevelWidth(boxSize.right - boxSize.left);
00952
00953
00954 }
00955 }
00956
00957
00958 iteration = currentIteration;
00959 return true;
00960 }
00961
00963 inline uint32 getWidthFromConstraint(const uint32 type, TableLayout::Column & col, const int32 availableWidthLessTableMinWidth, const int32 maxWidthLessMinWidth)
00964 {
00965 switch(type)
00966 {
00967
00968 case 0:
00969 return col.minimumWidth;
00970
00971 case 1:
00972 return col.maximumWidth;
00973
00974 case 2:
00975 {
00976 int32 d = (int32)col.maximumWidth - (int32)col.minimumWidth;
00977 return (uint32) ((int32)col.minimumWidth
00978 + (d * availableWidthLessTableMinWidth + (maxWidthLessMinWidth>>1))/maxWidthLessMinWidth);
00979 }
00980 default:
00981 return 0;
00982 }
00983 }
00984
00985
00987 inline uint32 computeHeightFromAvailableWidth(const uint32 width, const uint32 currentIteration)
00988 {
00989
00990 if (UID && UID->isTaggedAs(GenericElement::TABLE))
00991 {
00992
00993
00994
00995 TableLayout * tableLayout = mapper.getTableLayout(this);
00996 uint32 bottom = 0;
00997 if (tableLayout)
00998 {
00999 if (width < tableLayout->minimumWidth)
01000 assignWidthToTable(0, tableLayout, currentIteration, width, bottom);
01001 else if (width > tableLayout->maximumWidth)
01002 assignWidthToTable(1, tableLayout, currentIteration, width, bottom);
01003 else
01004 assignWidthToTable(2, tableLayout, currentIteration, width, bottom);
01005 }
01006 return bottom;
01007 }
01008
01009 bool isBlock = displayedAsBlock();
01010 if (!isBlock)
01011 {
01012 if (replacedElement())
01013 {
01014 if (declaredBox.content.height) return declaredBox.content.height->isAuto() ? getReplacedHeight() : declaredBox.content.height->getAsPixels(currentIteration);
01015 else return mapper.getMinimumHeightOf(this);
01016 }
01017 else
01018 {
01019 if (child)
01020 {
01021
01022 uint32 top, bottom;
01023
01024 top = mapper.findTopChildrenPos(this, false, false);
01025 bottom = mapper.findBottomChildrenPos(this, false, false);
01026
01027 return bottom - top;
01028 }
01029 else
01030 {
01031 uint32 minHeight = lineHeight.getHeightInPixels(boxFont, currentIteration);
01032 uint32 minWidth = mapper.getMinimumWidthOf(this);
01033
01034 if (minWidth + ((uint32)(declaredBox.border.getWidth(currentIteration) + declaredBox.margin.getWidth(currentIteration) + declaredBox.padding.getWidth(currentIteration)))> width)
01035 {
01036
01037 computedBox.content.width = width;
01038 setComputedValues();
01039
01040 splitLimit.right = width; splitLimit.left = 0;
01041
01042
01043
01044 findFirstBlockContainer();
01045 mapper.getSplitLimitsOf(this, splitLimit.left, splitLimit.right, computedPos.top, computedPos.left, computedPos.right, computedPos.bottom);
01046 minHeight = computedPos.bottom - computedPos.top;
01047 }
01048 return minHeight;
01049 }
01050 }
01051 } else
01052 {
01053 if (!declaredPos.absolutelyPositioned())
01054 {
01055 if (declaredBox.content.height && declaredBox.content.height->isAuto())
01056 {
01057 uint32 top = 0, bottom = 0;
01058 if (replacedElement())
01059 {
01060
01061 bottom = getReplacedHeight();
01062 } else
01063 {
01064
01065 if (mapper.hasBlockLevelChildren(this))
01066 {
01067
01068 top = computedPos.top;
01069 bottom = mapper.findBottomChildrenPos(this, true, false);
01070 } else
01071 {
01072 top = mapper.findTopChildrenPos(this, false, false);
01073 bottom = mapper.findBottomChildrenPos(this, false, false);
01074 }
01075 }
01076 return bottom - top;
01077 } else
01078 {
01079 return declaredBox.content.height ? declaredBox.content.height->getAsPixels(currentIteration) : 0;
01080 }
01081 }
01082 }
01083 return 0;
01084 }
01085
01087 inline void assignWidthToTable(const uint32 type, TableLayout * tableLayout, const uint32 currentIteration, const uint32 width, uint32 & bottom)
01088 {
01089 if (tableLayout)
01090 {
01091 uint32 maxColumn = tableLayout->realColumnCount();
01092 uint32 xOffset = 0, yOffset = 0;
01093 const int32 availableWidthLessTableMinWidth = (int32)width - (int32)tableLayout->minimumWidth;
01094 const int32 maxWidthLessMinWidth = (int32)tableLayout->maximumWidth - (int32)tableLayout->minimumWidth;
01095
01096
01097 Container::PlainOldData<uint32>::Array rowHeights;
01098 uint32 i = 0;
01099 for (; i < tableLayout->rowCount(); i++)
01100 {
01101 uint32 rowHeight = 0;
01102 uint32 j = 0;
01103 for (; j < maxColumn;)
01104 {
01105 uint32 cellWidth = getWidthFromConstraint(type, tableLayout->unsafeColumnAt(j), availableWidthLessTableMinWidth, maxWidthLessMinWidth);
01106 TableLayout::Cell * cell = tableLayout->findCellAt(i, j);
01107 if (!cell) break;
01108 for (uint32 z = 1; z < cell->horizontalSpan; z++)
01109 cellWidth += getWidthFromConstraint(type, tableLayout->unsafeColumnAt(j+z), availableWidthLessTableMinWidth, maxWidthLessMinWidth);
01110 j += cell->horizontalSpan;
01111 if (cell->verticalSpan > 1) continue;
01112
01113 Box * box = (Box*)cell->userData2;
01114 if (!box) continue;
01115 if (box->iteration >= currentIteration) continue;
01116
01117 box->computedPos.right = box->computedPos.left + cellWidth;
01118 uint32 height = box->computeHeightFromAvailableWidth(cellWidth, currentIteration);
01119 if (height > rowHeight) rowHeight = height;
01120 }
01121 rowHeights.Append(rowHeight);
01122 }
01123
01124
01125 for (i = 0; i < tableLayout->rowCount(); i++)
01126 {
01127 xOffset = 0;
01128 uint32 rowHeight = 0;
01129 uint32 j = 0;
01130 for (; j < maxColumn;)
01131 {
01132 uint32 cellWidth = getWidthFromConstraint(type, tableLayout->unsafeColumnAt(j), availableWidthLessTableMinWidth, maxWidthLessMinWidth);
01133 TableLayout::Cell * cell = tableLayout->findCellAt(i, j);
01134 if (!cell) break;
01135 uint32 z = 1;
01136 for (; z < cell->horizontalSpan; z++)
01137 cellWidth += getWidthFromConstraint(type, tableLayout->unsafeColumnAt(j+z), availableWidthLessTableMinWidth, maxWidthLessMinWidth);
01138 xOffset += cellWidth;
01139 j += cell->horizontalSpan;
01140 if (cell->verticalSpan <= 1) continue;
01141
01142 Box * box = (Box*)cell->userData2;
01143 if (!box) continue;
01144 if (box->iteration >= currentIteration) continue;
01145
01146 uint32 height = box->computeHeightFromAvailableWidth(cellWidth, currentIteration);
01147
01148 rowHeight = 0;
01149 for (z = 0; z < cell->verticalSpan; z++)
01150 rowHeight += rowHeights[i+z];
01151
01152 if (height > rowHeight)
01153 {
01154
01155 uint32 diff = height - rowHeight;
01156 for (z = 0; z < cell->verticalSpan; z++)
01157 rowHeights[i+z] += diff / cell->verticalSpan;
01158 }
01159 }
01160 }
01161
01162
01163 for (i = 0; i < tableLayout->rowCount(); i++)
01164 {
01165 xOffset = 0;
01166 for (uint32 j = 0; j < maxColumn; )
01167 {
01168 uint32 cellWidth = getWidthFromConstraint(type, tableLayout->unsafeColumnAt(j), availableWidthLessTableMinWidth, maxWidthLessMinWidth);
01169 TableLayout::Cell * cell = tableLayout->findCellAt(i, j);
01170 if (!cell) break;
01171 uint32 z = 1;
01172 for (; z < cell->horizontalSpan; z++)
01173 cellWidth += getWidthFromConstraint(type, tableLayout->unsafeColumnAt(j+z), availableWidthLessTableMinWidth, maxWidthLessMinWidth);
01174 j += cell->horizontalSpan;
01175
01176 Box * box = (Box*)cell->userData2;
01177 if (!box) continue;
01178 if (box->iteration < currentIteration)
01179 {
01180 box->transferDeclaredValues(false);
01181
01182 box->computedPos.top = computedPos.top + yOffset;
01183 box->computedPos.left = computedPos.left + xOffset;
01184 box->computedPos.right = box->computedPos.left + cellWidth;
01185
01186 box->computedBox.content.width = cellWidth;
01187 uint32 rowHeight = 0;
01188 for (z = 0; z < cell->verticalSpan; z++)
01189 rowHeight += rowHeights[i+z];
01190 box->computedPos.bottom = box->computedPos.top + rowHeight;
01191 box->computedBox.content.height = rowHeight;
01192
01193 box->iteration = currentIteration;
01194 }
01195 xOffset += cellWidth;
01196 }
01197 yOffset += rowHeights[i];
01198 }
01199 bottom = computedPos.top + yOffset;
01200 }
01201 }
01202
01204 inline void computeTableWidths(TableLayout::Cell * cellPtr, int32 & previousMaxWidth)
01205 {
01206
01207 int32 minimumWidth = 0, maximumWidth = 0;
01208
01209
01210 if (UID && UID->isTaggedAs(GenericElement::TABLE))
01211 {
01212
01213
01214
01215 TableLayout * tableLayout = mapper.getTableLayout(this);
01216 if (tableLayout)
01217 {
01218
01219 uint32 i = 0;
01220 for (i = 0; i < tableLayout->rowCount(); i++)
01221 {
01222 TableLayout::Row & row = (*tableLayout)[i];
01223 for (uint32 j = 0; j < row.cellCount(); j++)
01224 {
01225 TableLayout::Cell & currentCell = row[j];
01226
01227 Box * cellBox = (Box*)currentCell.userData2;
01228
01229 if (cellBox)
01230 {
01231 currentCell.minimumWidth = currentCell.maximumWidth = 0;
01232 int32 previousMaxWidth2 = 0;
01233 cellBox->computeTableWidths(¤tCell, previousMaxWidth2);
01234 }
01235 }
01236 }
01237
01238
01241 uint32 maxColumn = tableLayout->realColumnCount();
01242
01243 for (i = 0; i < maxColumn; i++)
01244 {
01245
01246 TableLayout::Column & col = tableLayout->unsafeColumnAt(i);
01247 col.minimumWidth = 0; col.maximumWidth = 0;
01248 for (uint32 j = 0; j < tableLayout->rowCount(); j++)
01249 {
01250 TableLayout::Cell * currentCell = tableLayout->findCellAt(j, i);
01251 if (!currentCell) break;
01252 if (currentCell->horizontalSpan > 1) continue;
01253 if (currentCell->minimumWidth > col.minimumWidth) col.minimumWidth = currentCell->minimumWidth;
01254 if (currentCell->maximumWidth > col.maximumWidth) col.maximumWidth = currentCell->maximumWidth;
01255 }
01256 }
01257
01258
01259
01260
01261 for (i = 0; i < tableLayout->rowCount(); i++)
01262 {
01263 for (uint32 j = 0; j < maxColumn; j++)
01264 {
01265 TableLayout::Cell * currentCell = tableLayout->findCellAt(i, j);
01266 if (!currentCell) break;
01267 if (currentCell->horizontalSpan <= 1) continue;
01268
01269
01270 uint32 sumMinWidth = 0;
01271 uint32 sumMaxWidth = 0;
01272
01273 uint32 z = 0;
01274 for (; z < currentCell->horizontalSpan; z++)
01275 {
01276 sumMinWidth += tableLayout->unsafeColumnAt(j+z).minimumWidth;
01277 sumMaxWidth += tableLayout->unsafeColumnAt(j+z).maximumWidth;
01278 }
01279
01280 if (sumMinWidth < currentCell->minimumWidth)
01281 {
01282
01283
01284
01285 uint32 missingWidth = currentCell->minimumWidth - sumMinWidth;
01286 for (z = 0; z < currentCell->horizontalSpan; z++)
01287 {
01288 uint32 & width = tableLayout->unsafeColumnAt(i+z).minimumWidth;
01289 width += sumMinWidth ? (missingWidth * width + (sumMinWidth >> 1)) / sumMinWidth : missingWidth / currentCell->horizontalSpan;
01290 }
01291 }
01292
01293 if (sumMaxWidth < currentCell->maximumWidth)
01294 {
01295
01296
01297 uint32 missingWidth = currentCell->maximumWidth - sumMaxWidth;
01298 for (z = 0; z < currentCell->horizontalSpan; z++)
01299 {
01300 uint32 & width = tableLayout->unsafeColumnAt(i+z).maximumWidth;
01301 width += sumMaxWidth ? (missingWidth * width + (sumMaxWidth >> 1)) / sumMaxWidth : missingWidth / currentCell->horizontalSpan;
01302 }
01303 }
01304
01305
01306 j += currentCell->horizontalSpan - 1;
01307 }
01308 }
01309
01310
01311 tableLayout->minimumWidth = tableLayout->maximumWidth = 0;
01312 for (i = 0; i < maxColumn; i++)
01313 {
01314
01315 TableLayout::Column & col = tableLayout->unsafeColumnAt(i);
01317 tableLayout->minimumWidth += col.minimumWidth;
01318 tableLayout->maximumWidth += col.maximumWidth;
01319 }
01320
01321
01322 minimumWidth = tableLayout->minimumWidth;
01323 maximumWidth = tableLayout->maximumWidth + previousMaxWidth;
01324 }
01325
01326 } else if (UID && UID->isTaggedAs(GenericElement::BR))
01327 {
01328 previousMaxWidth = 0;
01329 minimumWidth = maximumWidth = 0;
01330 } else
01331 {
01332
01333 mapper.getWidthsOf(this, minimumWidth, maximumWidth);
01334 }
01335
01336 if (cellPtr)
01337 {
01338 if (((const DOM::Element*)cellPtr->userData)->hasAttribute("NOWRAP"))
01339 {
01340
01341 minimumWidth = maximumWidth;
01342 }
01343
01344 if (cellPtr->minimumWidth < (uint32)minimumWidth) cellPtr->minimumWidth = minimumWidth;
01345
01346 if (previous)
01347 {
01348
01349 if (previous->displayedAsInline() && displayedAsInline())
01350 {
01351 previousMaxWidth += maximumWidth;
01352 maximumWidth = previousMaxWidth;
01353 } else
01354 {
01355 previousMaxWidth = 0;
01356 }
01357 } else if (displayedAsInline()) previousMaxWidth += maximumWidth;
01358 if (cellPtr->maximumWidth < (uint32)maximumWidth) cellPtr->maximumWidth = maximumWidth;
01359 if (previousMaxWidth > (int32)cellPtr->maximumWidth) cellPtr->maximumWidth = previousMaxWidth;
01360
01361
01362
01363
01364 if (child)
01365 child->computeTableWidths(cellPtr, previousMaxWidth);
01366
01367 if (next && (next->previous != (Box*)cellPtr->userData2))
01368 next->computeTableWidths(cellPtr, previousMaxWidth);
01369 }
01370 }
01371
01373 inline void transferWidthDeclaredValues(bool content = true, bool marginLeft = true, bool marginRight = true, bool borderLeft = true, bool borderRight = true, bool paddingLeft = true, bool paddingRight = true)
01374 {
01375 if (content) computedBox.content.width = declaredBox.content.getWidth(mapper.getCurrentIteration());
01376 if (borderLeft) computedBox.border.left = declaredBox.border.getLeftWidth(mapper.getCurrentIteration());
01377 if (borderRight) computedBox.border.right = declaredBox.border.getRightWidth(mapper.getCurrentIteration());
01378 if (paddingLeft) computedBox.padding.left = declaredBox.padding.getLeftWidth(mapper.getCurrentIteration());
01379 if (paddingRight) computedBox.padding.right = declaredBox.padding.getRightWidth(mapper.getCurrentIteration());
01380 if (marginLeft) computedBox.margin.left = declaredBox.margin.getLeftWidth(mapper.getCurrentIteration());
01381 if (marginRight) computedBox.margin.right = declaredBox.margin.getRightWidth(mapper.getCurrentIteration());
01382 }
01383
01385 inline void setComputedWidthValues()
01386 {
01387 uint32 iteration = mapper.getCurrentIteration();
01388 declaredBox.content.setComputedWidth(computedBox.content.width, iteration);
01389 declaredBox.border.setLeftWidth(computedBox.border.left, iteration);
01390 declaredBox.border.setRightWidth(computedBox.border.right, iteration);
01391 declaredBox.padding.setLeftWidth(computedBox.padding.left, iteration);
01392 declaredBox.padding.setRightWidth(computedBox.padding.right, iteration);
01393 declaredBox.margin.setLeftWidth(computedBox.margin.left, iteration);
01394 declaredBox.margin.setRightWidth(computedBox.margin.right, iteration);
01395 }
01396
01398 inline void transferHeightDeclaredValues(bool content = true, bool marginTop = true, bool marginBottom = true, bool borderTop = true, bool borderBottom = true, bool paddingTop = true, bool paddingBottom = true)
01399 {
01400 if (content) computedBox.content.height = declaredBox.content.getHeight(mapper.getCurrentIteration());
01401 if (borderTop) computedBox.border.top = declaredBox.border.getTopWidth(mapper.getCurrentIteration());
01402 if (borderBottom) computedBox.border.bottom = declaredBox.border.getBottomWidth(mapper.getCurrentIteration());
01403 if (paddingTop) computedBox.padding.top = declaredBox.padding.getTopWidth(mapper.getCurrentIteration());
01404 if (paddingBottom) computedBox.padding.bottom = declaredBox.padding.getBottomWidth(mapper.getCurrentIteration());
01405 if (marginTop) computedBox.margin.top = declaredBox.margin.getTopWidth(mapper.getCurrentIteration());
01406 if (marginBottom) computedBox.margin.bottom = declaredBox.margin.getBottomWidth(mapper.getCurrentIteration());
01407 }
01408
01410 inline void setComputedHeightValues()
01411 {
01412 uint32 iteration = mapper.getCurrentIteration();
01413 declaredBox.content.setComputedHeight(computedBox.content.height, iteration);
01414 declaredBox.border.setTopHeight(computedBox.border.top, iteration);
01415 declaredBox.border.setBottomHeight(computedBox.border.bottom, iteration);
01416 declaredBox.padding.setTopHeight(computedBox.padding.top, iteration);
01417 declaredBox.padding.setBottomHeight(computedBox.padding.bottom, iteration);
01418 declaredBox.margin.setTopHeight(computedBox.margin.top, iteration);
01419 declaredBox.margin.setBottomHeight(computedBox.margin.bottom, iteration);
01420 }
01421
01422
01424 inline void setComputedPosValues(const int32 left, const int32 right)
01425 {
01426 uint32 iteration = mapper.getCurrentIteration();
01427 declaredPos.setLeft(left, iteration); declaredPos.setRight(right, iteration);
01428 }
01429
01431 inline void setComputedValues() { setComputedWidthValues(); setComputedHeightValues(); }
01433 inline void transferDeclaredValues(bool content = true, bool margin1 = true, bool margin2 = true, bool border1 = true, bool border2 = true, bool padding1 = true , bool padding2 = true) { transferWidthDeclaredValues(content, margin1, margin2, border1, border2, padding1, padding2); transferHeightDeclaredValues(content, margin1, margin2, border1, border2, padding1, padding2); }
01434
01435
01438 inline void solveBlockLevelWidth(uint32 width)
01439 {
01440
01441
01442 bool marginLeft = declaredBox.margin.left && !declaredBox.margin.left->isAuto();
01443 bool marginRight = declaredBox.margin.right && !declaredBox.margin.right->isAuto();
01444 bool widthSet = declaredBox.content.width && !declaredBox.content.width->isAuto();
01445
01446
01447 transferWidthDeclaredValues(widthSet, marginLeft, marginRight);
01448
01449 if (marginLeft && marginRight && widthSet)
01450 {
01451
01452 int newMarginWidth = (int)width - (int)declaredBox.margin.getWidth(mapper.getCurrentIteration()) - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - (int)declaredBox.padding.getWidth(mapper.getCurrentIteration());
01453
01454 leftToRight ? computedBox.margin.right = newMarginWidth : computedBox.margin.left = newMarginWidth;
01455
01456 setComputedWidthValues();
01457 return;
01458 }
01459
01460
01461 if (!widthSet && replacedElement())
01462 {
01463 computedBox.content.width = getReplacedWidth();
01464 } else if (!widthSet)
01465 {
01466
01467 if (!marginLeft) computedBox.margin.left = 0;
01468 if (!marginRight) computedBox.margin.right = 0;
01469
01470 int newWidth = (int)width - computedBox.margin.getWidth() - computedBox.padding.getWidth() - computedBox.border.getWidth();
01471 if (newWidth >= 0)
01472 {
01473 computedBox.content.width = (uint32)newWidth;
01474 } else
01475 {
01476 computedBox.content.width = 0;
01477
01478 if (leftToRight)
01479 {
01480 newWidth = (int)width - computedBox.padding.getWidth() - computedBox.border.getWidth() - computedBox.margin.left;
01481
01482 computedBox.margin.right = newWidth;
01483 } else
01484 {
01485 newWidth = (int)width - computedBox.padding.getWidth() - computedBox.border.getWidth() - computedBox.margin.right;
01486
01487 computedBox.margin.left = newWidth;
01488 }
01489 }
01490 setComputedWidthValues();
01491 return;
01492 }
01493
01494
01495 if (!marginLeft && !marginRight)
01496 {
01497 int newWidth = (int)width - computedBox.content.width - computedBox.padding.getWidth() - computedBox.border.getWidth();
01498 if (newWidth >= 0)
01499 {
01500 computedBox.margin.left = computedBox.margin.right = newWidth / 2;
01501
01502 if (newWidth & 1) computedBox.margin.left ++;
01503 } else
01504 {
01505 computedBox.margin.left = 0; computedBox.margin.right = newWidth;
01506 }
01507 setComputedWidthValues();
01508 return;
01509 }
01510
01511 if (!marginLeft)
01512 {
01513 int newWidth = (int)width - computedBox.content.width - computedBox.padding.getWidth() - computedBox.border.getWidth() - computedBox.margin.right;
01514 if (newWidth >= 0)
01515 computedBox.margin.left = newWidth;
01516 else
01517 {
01518 computedBox.margin.left = 0; computedBox.margin.right = newWidth;
01519 }
01520 } else
01521 {
01522 int newWidth = (int)width - computedBox.content.width - computedBox.padding.getWidth() - computedBox.border.getWidth() - computedBox.margin.left;
01523 computedBox.margin.right = newWidth;
01524 }
01525 setComputedWidthValues();
01526 return;
01527 }
01528
01531 inline void solveAbsoluteBlockLevelWidth(uint32 width)
01532 {
01533
01534
01535 bool left = declaredPos.left && !declaredPos.left->isAuto();
01536 bool right = declaredPos.right && !declaredPos.right->isAuto();
01537 bool marginLeft = declaredBox.margin.left && !declaredBox.margin.left->isAuto();
01538 bool marginRight = declaredBox.margin.right && !declaredBox.margin.right->isAuto();
01539 bool widthSet = declaredBox.content.width && !declaredBox.content.width->isAuto();
01540
01541 transferWidthDeclaredValues(widthSet, marginLeft, marginRight);
01542 int32 leftValue = declaredPos.getLeft(mapper.getCurrentIteration()), rightValue = declaredPos.getRight(mapper.getCurrentIteration()), marginLeftValue = declaredBox.margin.getLeftWidth(mapper.getCurrentIteration()), marginRightValue = declaredBox.margin.getRightWidth(mapper.getCurrentIteration()), widthValue = declaredBox.content.getWidth(mapper.getCurrentIteration());
01543 uint32 mask = (left ? 1 : 0) | (right ? 2 : 0) | (marginLeft ? 4 : 0) | (marginRight ? 8 : 0) | (widthSet ? 16 : 0);
01544 if (!widthSet && replacedElement())
01545 {
01546 widthValue = getReplacedWidth();
01547 mask |= 16;
01548 }
01549
01550 while (1)
01551 {
01552 switch (mask)
01553 {
01554
01555 case 31:
01556 if (leftToRight)
01557 rightValue = (int)width - marginLeftValue - marginRightValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - widthValue - leftValue;
01558 else
01559 leftValue = (int)width - marginLeftValue - marginRightValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - widthValue - rightValue;
01560 break;
01561
01562
01563 case 15:
01564 widthValue = (int)width - marginLeftValue - marginRightValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - leftValue - rightValue;
01565 mask = 31;
01566 break;
01567
01568 case 23:
01569 marginRightValue = (int)width - marginLeftValue - widthValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - leftValue - rightValue;
01570 mask = 31;
01571 break;
01572
01573 case 27:
01574 marginLeftValue = (int)width - marginRightValue - widthValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - leftValue - rightValue;
01575 mask = 31;
01576 break;
01577
01578 case 29:
01579 rightValue = (int)width - marginRightValue - widthValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - leftValue - marginLeftValue;
01580 mask = 31;
01581 break;
01582
01583 case 30:
01584 leftValue = (int)width - marginRightValue - widthValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - rightValue - marginLeftValue;
01585 mask = 31;
01586 break;
01587
01588
01589 case 19:
01590 {
01591 int margin = (int)width - widthValue - (int)declaredBox.border.getWidth(mapper.getCurrentIteration()) - declaredBox.padding.getWidth(mapper.getCurrentIteration()) - rightValue - leftValue;
01592 marginLeftValue = (margin / 2) + (margin % 1);
01593 marginRightValue = (margin / 2);
01594 mask = 31;
01595 break;
01596 }
01597
01598 default:
01599 break;
01600 }
01601
01602 if (mask == 31)
01603 {
01604 computedPos.left += leftValue;
01605 computedPos.right -= rightValue;
01606 computedBox.margin.left = marginLeftValue;
01607 computedBox.margin.right = marginRightValue;
01608 computedBox.content.width = widthValue;
01609 setComputedPosValues(leftValue, rightValue);
01610 setComputedWidthValues();
01611 return;
01612 } else if ((mask & 1) == 0 && leftToRight)
01613 {
01614 leftValue = 0;
01615 mask |= 1;
01616 } else if ((mask & 2) == 0 && !leftToRight)
01617 {
01618 rightValue = 0;
01619 mask |= 2;
01620 } else if ((mask & 16) == 0)
01621 {
01622 if ((mask & 1) == 0) { leftValue = 0; mask |= 1; }
01623 if ((mask & 2) == 0) { rightValue = 0; mask |= 2; }
01624 } else if ( (!replacedElement() && (mask & 16) == 0) || (mask & 1) == 0 || (mask & 2) == 0)
01625 {
01626 if ((mask & 4) == 0) { marginLeftValue = 0; mask |= 4; }
01627 if ((mask & 8) == 0) { marginRightValue = 0; mask |= 8; }
01628 }
01629 }
01630 }
01631
01633 inline void zeroIfAuto(Length * len) const
01634 {
01635 if (len && len->isAuto()) len->setComputedValue(0, mapper.getCurrentIteration());
01636 }
01637
01639 inline void getContentPosition(ComputedPosition & box) const
01640 { box = computedPos;
01641 box.top += computedBox.border.top + computedBox.margin.top + computedBox.padding.top;
01642 box.left += computedBox.border.left + computedBox.margin.left + computedBox.padding.left;
01643 box.right -= computedBox.border.right + computedBox.margin.right + computedBox.padding.right;
01644 box.bottom -= computedBox.border.bottom + computedBox.margin.bottom + computedBox.padding.bottom; }
01645
01647 inline uint32 getContainedBlockWidth() const { return computedBox.padding.getWidth() + computedBox.content.getWidth(); }
01649 inline uint32 getContainedBlockHeight() const { return computedBox.padding.getHeight() + computedBox.content.getHeight(); }
01650
01651
01653 inline uint32 getBlockWidth() const { return getContainedBlockWidth() + computedBox.border.getWidth() + computedBox.margin.getTrueWidth(); }
01655 inline uint32 getBlockHeight() const { return getContainedBlockHeight() + computedBox.border.getHeight() + computedBox.margin.getTrueHeight(); }
01656
01658 inline bool displayedAsBlock() const { return displayMode == CSS::DisplayMode::Block || displayMode == CSS::DisplayMode::ListItem || displayMode == CSS::DisplayMode::Compact || displayMode == CSS::DisplayMode::RunIn || displayMode == CSS::DisplayMode::Table || displayMode == CSS::DisplayMode::TableCell; }
01660 inline bool displayedAsInline() const { return displayMode == CSS::DisplayMode::Inline || displayMode == CSS::DisplayMode::InlineTable || displayMode == CSS::DisplayMode::Compact || displayMode == CSS::DisplayMode::RunIn; }
01661
01663 inline bool isFloating() const { return clearAndFloat.getFloat() != CSS::ClearAndFloat::None ; }
01665 inline bool isCleared() const { return clearAndFloat.getClear() != CSS::ClearAndFloat::None ; }
01666
01668 inline bool isSplit() const { return splitLimit.left != splitLimit.right; }
01670 inline int32 getSplitRightPosition() const { return splitLimit.right; }
01672 inline int32 getSplitLeftPosition() const { return splitLimit.left; }
01673
01675 inline bool replacedElement() const { return contentType > Text && contentType < Table; }
01677 uint32 getReplacedWidth() { return mapper.getRenderedWidthOf(this); }
01679 uint32 getReplacedHeight() { return mapper.getRenderedHeightOf(this); }
01680
01684 inline const Border::Side & getBorderSide(uint32 whichOne) const { switch (whichOne) { case 0: return declaredBox.border.top; case 1: return declaredBox.border.left; case 2: return declaredBox.border.right; default: return declaredBox.border.bottom; } }
01687 inline bool hasBackground() const { return false; }
01688
01690 inline Box * findPreviousBox() const
01691 {
01692 if (previous) return previous;
01693
01694 if (ancestor && !ancestor->displayedAsBlock()) return ancestor;
01695
01696 return 0;
01697 }
01698
01700 inline void returnAllLengths(volatile const HTML::Renderer::Allocators::BaseAllocator * alloc)
01701 {
01702 if (!alloc) return;
01703
01704 alloc->returnLength(declaredBox.content.width);
01705 alloc->returnLength(declaredBox.content.height);
01706
01707 alloc->returnLength(declaredBox.border.top.length);
01708 alloc->returnLength(declaredBox.border.left.length);
01709 alloc->returnLength(declaredBox.border.right.length);
01710 alloc->returnLength(declaredBox.border.bottom.length);
01711
01712 alloc->returnLength(declaredBox.padding.top);
01713 alloc->returnLength(declaredBox.padding.left);
01714 alloc->returnLength(declaredBox.padding.right);
01715 alloc->returnLength(declaredBox.padding.bottom);
01716
01717 alloc->returnLength(declaredBox.margin.top);
01718 alloc->returnLength(declaredBox.margin.left);
01719 alloc->returnLength(declaredBox.margin.right);
01720 alloc->returnLength(declaredBox.margin.bottom);
01721
01722
01723 alloc->returnLength(declaredPos.top);
01724 alloc->returnLength(declaredPos.left);
01725 alloc->returnLength(declaredPos.right);
01726 alloc->returnLength(declaredPos.bottom);
01727
01728
01729 alloc->returnLength(lineHeight.setNotOwnedLength(0));
01730 }
01731
01732 public:
01738
01739
01743 Box(Mapper & _mapper, const BoxHierarchy * boxHierarchy, const CSS::StyleImplement & style, const ContentType ct = Text, const Strings::FastString & text = "")
01744 : mapper(_mapper), UID(boxHierarchy), iteration(0), renderAsAnonymousBlock(false), splitLimit(0, 0),
01745 declaredBox( style.contentWidth, style.contentHeight,
01746 style.paddingTop, style.paddingLeft, style.paddingRight, style.paddingBottom,
01747 style.marginTop, style.marginLeft, style.marginRight, style.marginBottom,
01748 style.borderTop, style.borderTopStyle, style.borderTopColor,
01749 style.borderLeft, style.borderLeftStyle, style.borderLeftColor,
01750 style.borderRight, style.borderRightStyle, style.borderRightColor,
01751 style.borderBottom, style.borderBottomStyle, style.borderBottomColor),
01752 declaredPos(style.positionType, style.positionTop, style.positionLeft, style.positionRight, style.positionBottom),
01753 displayMode(style.displayMode),
01754 leftToRight(style.leftToRight),
01755 lineHeight(style.lineHeight), boxFont(style.font),
01756 clearAndFloat(style.floating, style.clearing),
01757 contentType(ct), contentText(text),
01758 textAlign(style.textAlign), verticalAlign(style.verticalAlign), textDecoration(style.textDecoration),
01759 ancestor(0), previous(0), next(0), container(0), child(0)
01760 {}
01761
01762
01763
01764 public:
01765 friend class Mapper;
01766 };
01767 }
01768 }
01769
01770
01771
01772 #endif