static bool shouldScaleColumns(RenderTable* table) { // A special case. If this table is not fixed width and contained inside // a cell, then don't bloat the maxwidth by examining percentage growth. bool scale = true; while (table) { Length tw = table->style()->width(); if ((tw.isVariable() || tw.isPercent()) && !table->isPositioned()) { RenderBlock* cb = table->containingBlock(); while (cb && !cb->isCanvas() && !cb->isTableCell() && cb->style()->width().isVariable() && !cb->isPositioned()) cb = cb->containingBlock(); table = 0; if (cb && cb->isTableCell() && (cb->style()->width().isVariable() || cb->style()->width().isPercent())) { if (tw.isPercent()) scale = false; else { RenderTableCell* cell = static_cast<RenderTableCell*>(cb); if (cell->colSpan() > 1 || cell->table()->style()->width().isVariable()) scale = false; else table = cell->table(); } } } else table = 0; } return scale; }
static inline bool hasAutoHeightOrContainingBlockWithAutoHeight(const RenderReplaced* replaced) { Length logicalHeightLength = replaced->style()->logicalHeight(); if (logicalHeightLength.isAuto()) return true; // For percentage heights: The percentage is calculated with respect to the height of the generated box's // containing block. If the height of the containing block is not specified explicitly (i.e., it depends // on content height), and this element is not absolutely positioned, the value computes to 'auto'. if (!logicalHeightLength.isPercent() || replaced->isPositioned() || replaced->document()->inQuirksMode()) return false; for (RenderBlock* cb = replaced->containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { if (cb->isTableCell() || (!cb->style()->logicalHeight().isAuto() || (!cb->style()->top().isAuto() && !cb->style()->bottom().isAuto()))) return false; } return true; }
bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const { Length logicalHeightLength = style()->logicalHeight(); if (logicalHeightLength.isAuto()) return true; // For percentage heights: The percentage is calculated with respect to the height of the generated box's // containing block. If the height of the containing block is not specified explicitly (i.e., it depends // on content height), and this element is not absolutely positioned, the value computes to 'auto'. if (!logicalHeightLength.isPercent() || isOutOfFlowPositioned() || document().inQuirksMode()) return false; // Anonymous block boxes are ignored when resolving percentage values that would refer to it: // the closest non-anonymous ancestor box is used instead. RenderBlock* cb = containingBlock(); while (cb->isAnonymous()) cb = cb->containingBlock(); // Matching RenderBox::percentageLogicalHeightIsResolvableFromBlock() by // ignoring table cell's attribute value, where it says that table cells violate // what the CSS spec says to do with heights. Basically we // don't care if the cell specified a height or not. if (cb->isTableCell()) return false; // Match RenderBox::availableLogicalHeightUsing by special casing // the render view. The available height is taken from the frame. if (cb->isRenderView()) return false; if (cb->isOutOfFlowPositioned() && !cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto()) return false; // If the height of the containing block computes to 'auto', then it hasn't been 'specified explicitly'. return cb->hasAutoHeightOrContainingBlockWithAutoHeight(); }
void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTextBehavior behavior) { ts << o.renderName(); if (behavior & RenderAsTextShowAddresses) ts << " " << static_cast<const void*>(&o); if (o.style() && o.style()->zIndex()) ts << " zI: " << o.style()->zIndex(); if (o.node()) { String tagName = getTagName(o.node()); if (!tagName.isEmpty()) { ts << " {" << tagName << "}"; // flag empty or unstyled AppleStyleSpan because we never // want to leave them in the DOM if (isEmptyOrUnstyledAppleStyleSpan(o.node())) ts << " *empty or unstyled AppleStyleSpan*"; } } RenderBlock* cb = o.containingBlock(); bool adjustForTableCells = cb ? cb->isTableCell() : false; LayoutRect r; if (o.isText()) { // FIXME: Would be better to dump the bounding box x and y rather than the first run's x and y, but that would involve updating // many test results. const RenderText& text = *toRenderText(&o); IntRect linesBox = text.linesBoundingBox(); r = IntRect(text.firstRunX(), text.firstRunY(), linesBox.width(), linesBox.height()); if (adjustForTableCells && !text.firstTextBox()) adjustForTableCells = false; } else if (o.isRenderInline()) { // FIXME: Would be better not to just dump 0, 0 as the x and y here. const RenderInline& inlineFlow = *toRenderInline(&o); r = IntRect(0, 0, inlineFlow.linesBoundingBox().width(), inlineFlow.linesBoundingBox().height()); adjustForTableCells = false; } else if (o.isTableCell()) { // FIXME: Deliberately dump the "inner" box of table cells, since that is what current results reflect. We'd like // to clean up the results to dump both the outer box and the intrinsic padding so that both bits of information are // captured by the results. const RenderTableCell& cell = *toRenderTableCell(&o); r = LayoutRect(cell.x(), cell.y() + cell.intrinsicPaddingBefore(), cell.width(), cell.height() - cell.intrinsicPaddingBefore() - cell.intrinsicPaddingAfter()); } else if (o.isBox()) r = toRenderBox(&o)->frameRect(); // FIXME: Temporary in order to ensure compatibility with existing layout test results. if (adjustForTableCells) r.move(0, -toRenderTableCell(o.containingBlock())->intrinsicPaddingBefore()); // FIXME: Convert layout test results to report sub-pixel values, in the meantime using enclosingIntRect // for consistency with old results. ts << " " << enclosingIntRect(r); if (!(o.isText() && !o.isBR())) { if (o.isFileUploadControl()) ts << " " << quoteAndEscapeNonPrintables(toRenderFileUploadControl(&o)->fileTextValue()); if (o.parent()) { Color color = o.style()->visitedDependentColor(CSSPropertyColor); if (o.parent()->style()->visitedDependentColor(CSSPropertyColor) != color) ts << " [color=" << color.nameForRenderTreeAsText() << "]"; // Do not dump invalid or transparent backgrounds, since that is the default. Color backgroundColor = o.style()->visitedDependentColor(CSSPropertyBackgroundColor); if (o.parent()->style()->visitedDependentColor(CSSPropertyBackgroundColor) != backgroundColor && backgroundColor.isValid() && backgroundColor.rgb()) ts << " [bgcolor=" << backgroundColor.nameForRenderTreeAsText() << "]"; Color textFillColor = o.style()->visitedDependentColor(CSSPropertyWebkitTextFillColor); if (o.parent()->style()->visitedDependentColor(CSSPropertyWebkitTextFillColor) != textFillColor && textFillColor.isValid() && textFillColor != color && textFillColor.rgb()) ts << " [textFillColor=" << textFillColor.nameForRenderTreeAsText() << "]"; Color textStrokeColor = o.style()->visitedDependentColor(CSSPropertyWebkitTextStrokeColor); if (o.parent()->style()->visitedDependentColor(CSSPropertyWebkitTextStrokeColor) != textStrokeColor && textStrokeColor.isValid() && textStrokeColor != color && textStrokeColor.rgb()) ts << " [textStrokeColor=" << textStrokeColor.nameForRenderTreeAsText() << "]"; if (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth() && o.style()->textStrokeWidth() > 0) ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]"; } if (!o.isBoxModelObject()) return; const RenderBoxModelObject& box = *toRenderBoxModelObject(&o); if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) { ts << " [border:"; BorderValue prevBorder = o.style()->borderTop(); if (!box.borderTop()) ts << " none"; else { ts << " (" << box.borderTop() << "px "; printBorderStyle(ts, o.style()->borderTopStyle()); Color col = o.style()->borderTopColor(); if (!col.isValid()) col = o.style()->color(); ts << col.nameForRenderTreeAsText() << ")"; } if (o.style()->borderRight() != prevBorder) { prevBorder = o.style()->borderRight(); if (!box.borderRight()) ts << " none"; else { ts << " (" << box.borderRight() << "px "; printBorderStyle(ts, o.style()->borderRightStyle()); Color col = o.style()->borderRightColor(); if (!col.isValid()) col = o.style()->color(); ts << col.nameForRenderTreeAsText() << ")"; } } if (o.style()->borderBottom() != prevBorder) { prevBorder = box.style()->borderBottom(); if (!box.borderBottom()) ts << " none"; else { ts << " (" << box.borderBottom() << "px "; printBorderStyle(ts, o.style()->borderBottomStyle()); Color col = o.style()->borderBottomColor(); if (!col.isValid()) col = o.style()->color(); ts << col.nameForRenderTreeAsText() << ")"; } } if (o.style()->borderLeft() != prevBorder) { prevBorder = o.style()->borderLeft(); if (!box.borderLeft()) ts << " none"; else { ts << " (" << box.borderLeft() << "px "; printBorderStyle(ts, o.style()->borderLeftStyle()); Color col = o.style()->borderLeftColor(); if (!col.isValid()) col = o.style()->color(); ts << col.nameForRenderTreeAsText() << ")"; } } ts << "]"; } #if ENABLE(MATHML) // We want to show any layout padding, both CSS padding and intrinsic padding, so we can't just check o.style()->hasPadding(). if (o.isRenderMathMLBlock() && (box.paddingTop() || box.paddingRight() || box.paddingBottom() || box.paddingLeft())) { ts << " ["; LayoutUnit cssTop = box.computedCSSPaddingTop(); LayoutUnit cssRight = box.computedCSSPaddingRight(); LayoutUnit cssBottom = box.computedCSSPaddingBottom(); LayoutUnit cssLeft = box.computedCSSPaddingLeft(); if (box.paddingTop() != cssTop || box.paddingRight() != cssRight || box.paddingBottom() != cssBottom || box.paddingLeft() != cssLeft) { ts << "intrinsic "; if (cssTop || cssRight || cssBottom || cssLeft) ts << "+ CSS "; } ts << "padding: " << roundToInt(box.paddingTop()) << " " << roundToInt(box.paddingRight()) << " " << roundToInt(box.paddingBottom()) << " " << roundToInt(box.paddingLeft()) << "]"; } #endif } if (o.isTableCell()) { const RenderTableCell& c = *toRenderTableCell(&o); ts << " [r=" << c.rowIndex() << " c=" << c.col() << " rs=" << c.rowSpan() << " cs=" << c.colSpan() << "]"; } #if ENABLE(DETAILS_ELEMENT) if (o.isDetailsMarker()) { ts << ": "; switch (toRenderDetailsMarker(&o)->orientation()) { case RenderDetailsMarker::Left: ts << "left"; break; case RenderDetailsMarker::Right: ts << "right"; break; case RenderDetailsMarker::Up: ts << "up"; break; case RenderDetailsMarker::Down: ts << "down"; break; } } #endif if (o.isListMarker()) { String text = toRenderListMarker(&o)->text(); if (!text.isEmpty()) { if (text.length() != 1) text = quoteAndEscapeNonPrintables(text); else { switch (text[0]) { case bullet: text = "bullet"; break; case blackSquare: text = "black square"; break; case whiteBullet: text = "white bullet"; break; default: text = quoteAndEscapeNonPrintables(text); } } ts << ": " << text; } } if (behavior & RenderAsTextShowIDAndClass) { if (Node* node = o.node()) { if (node->hasID()) ts << " id=\"" + static_cast<Element*>(node)->getIdAttribute() + "\""; if (node->hasClass()) { ts << " class=\""; StyledElement* styledElement = static_cast<StyledElement*>(node); for (size_t i = 0; i < styledElement->classNames().size(); ++i) { if (i > 0) ts << " "; ts << styledElement->classNames()[i]; } ts << "\""; } } } if (behavior & RenderAsTextShowLayoutState) { bool needsLayout = o.selfNeedsLayout() || o.needsPositionedMovementLayout() || o.posChildNeedsLayout() || o.normalChildNeedsLayout(); if (needsLayout) ts << " (needs layout:"; bool havePrevious = false; if (o.selfNeedsLayout()) { ts << " self"; havePrevious = true; } if (o.needsPositionedMovementLayout()) { if (havePrevious) ts << ","; havePrevious = true; ts << " positioned movement"; } if (o.normalChildNeedsLayout()) { if (havePrevious) ts << ","; havePrevious = true; ts << " child"; } if (o.posChildNeedsLayout()) { if (havePrevious) ts << ","; ts << " positioned child"; } if (needsLayout) ts << ")"; } #if PLATFORM(QT) // Print attributes of embedded QWidgets. E.g. when the WebCore::Widget // is invisible the QWidget should be invisible too. if (o.isRenderPart()) { const RenderPart* part = toRenderPart(const_cast<RenderObject*>(&o)); if (part->widget() && part->widget()->platformWidget()) { QObject* wid = part->widget()->platformWidget(); ts << " [QT: "; ts << "geometry: {" << wid->property("geometry").toRect() << "} "; ts << "isHidden: " << !wid->property("isVisible").toBool() << " "; ts << "isSelfVisible: " << part->widget()->isSelfVisible() << " "; ts << "isParentVisible: " << part->widget()->isParentVisible() << " ] "; } } #endif }