diff options
Diffstat (limited to 'Source/WebCore/rendering')
| -rw-r--r-- | Source/WebCore/rendering/FilterEffectRenderer.h | 2 | ||||
| -rw-r--r-- | Source/WebCore/rendering/InlineBox.h | 2 | ||||
| -rw-r--r-- | Source/WebCore/rendering/InlineTextBox.cpp | 9 | ||||
| -rw-r--r-- | Source/WebCore/rendering/InlineTextBox.h | 5 | ||||
| -rwxr-xr-x | Source/WebCore/rendering/RenderBlockLineLayout.cpp | 8 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderBox.h | 2 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderButton.cpp | 36 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderButton.h | 6 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderLayer.cpp | 30 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderLayer.h | 2 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderListBox.cpp | 33 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderListBox.h | 2 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderObject.h | 2 | ||||
| -rw-r--r-- | Source/WebCore/rendering/RenderText.cpp | 1 | ||||
| -rw-r--r-- | Source/WebCore/rendering/TextAutosizer.cpp | 188 | ||||
| -rw-r--r-- | Source/WebCore/rendering/TextAutosizer.h | 18 | ||||
| -rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGModelObject.cpp | 7 | ||||
| -rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGModelObject.h | 1 |
18 files changed, 278 insertions, 76 deletions
diff --git a/Source/WebCore/rendering/FilterEffectRenderer.h b/Source/WebCore/rendering/FilterEffectRenderer.h index bc53cdc14..4304e1671 100644 --- a/Source/WebCore/rendering/FilterEffectRenderer.h +++ b/Source/WebCore/rendering/FilterEffectRenderer.h @@ -113,7 +113,7 @@ public: bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; } LayoutRect computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect); -#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) +#if ENABLE(CSS_SHADERS) bool hasCustomShaderFilter() const { return m_hasCustomShaderFilter; } #endif private: diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h index d8f7e3c17..a6b94debb 100644 --- a/Source/WebCore/rendering/InlineBox.h +++ b/Source/WebCore/rendering/InlineBox.h @@ -262,7 +262,7 @@ public: virtual void clearTruncation() { } bool isDirty() const { return m_bitfields.dirty(); } - void markDirty(bool dirty = true) { m_bitfields.setDirty(dirty); } + virtual void markDirty(bool dirty = true) { m_bitfields.setDirty(dirty); } virtual void dirtyLineBoxes(); diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 5bc3b7652..95a6f0239 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -64,6 +64,15 @@ void InlineTextBox::destroy(RenderArena* arena) InlineBox::destroy(arena); } +void InlineTextBox::markDirty(bool dirty) +{ + if (dirty) { + m_len = 0; + m_start = 0; + } + InlineBox::markDirty(dirty); +} + LayoutRect InlineTextBox::logicalOverflowRect() const { if (knownToHaveNoOverflow() || !gTextBoxesWithOverflow) diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index 06ba040fc..9a8451578 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -64,6 +64,7 @@ public: void setNextTextBox(InlineTextBox* n) { m_nextTextBox = n; } void setPreviousTextBox(InlineTextBox* p) { m_prevTextBox = p; } + // FIXME: These accessors should ASSERT(!isDirty()). See https://bugs.webkit.org/show_bug.cgi?id=97264 unsigned start() const { return m_start; } unsigned end() const { return m_len ? m_start + m_len - 1 : m_start; } unsigned len() const { return m_len; } @@ -71,10 +72,12 @@ public: void setStart(unsigned start) { m_start = start; } void setLen(unsigned len) { m_len = len; } - void offsetRun(int d) { m_start += d; } + void offsetRun(int d) { ASSERT(!isDirty()); m_start += d; } unsigned short truncation() { return m_truncation; } + virtual void markDirty(bool dirty = true) OVERRIDE; + using InlineBox::hasHyphen; using InlineBox::setHasHyphen; using InlineBox::canHaveLeadingExpansion; diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index cbcc988aa..bfe03b804 100755 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -2414,10 +2414,6 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol float wordSpacing = currentStyle->wordSpacing(); float lastSpaceWordSpacing = 0; - // Non-zero only when kerning is enabled, in which case we measure words with their trailing - // space, then subtract its width. - float wordTrailingSpaceWidth = f.typesettingFeatures() & Kerning ? f.width(constructTextRun(t, f, &space, 1, style)) + wordSpacing : 0; - float wrapW = width.uncommittedWidth() + inlineLogicalWidth(current.m_obj, !appliedStartWidth, true); float charWidth = 0; bool breakNBSP = autoWrap && currentStyle->nbspMode() == SPACE; @@ -2447,6 +2443,10 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol TextLayout* textLayout = renderTextInfo.m_layout.get(); + // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure + // words with their trailing space, then subtract its width. + float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) && !textLayout ? f.width(constructTextRun(t, f, &space, 1, style)) + wordSpacing : 0; + for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) { bool previousCharacterIsSpace = currentCharacterIsSpace; bool previousCharacterIsWS = currentCharacterIsWS; diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 8b580e112..db274fb84 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -366,7 +366,7 @@ public: virtual void updateLogicalWidth(); virtual void updateLogicalHeight(); - void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const; + virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const; RenderBoxRegionInfo* renderBoxRegionInfo(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const; void computeLogicalWidthInRegion(LogicalExtentComputedValues&, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = ZERO_LAYOUT_UNIT) const; diff --git a/Source/WebCore/rendering/RenderButton.cpp b/Source/WebCore/rendering/RenderButton.cpp index c59c82216..7103e6e50 100644 --- a/Source/WebCore/rendering/RenderButton.cpp +++ b/Source/WebCore/rendering/RenderButton.cpp @@ -35,6 +35,7 @@ using namespace HTMLNames; RenderButton::RenderButton(Node* node) : RenderDeprecatedFlexibleBox(node) + , m_buttonText(0) , m_inner(0) , m_default(false) { @@ -82,6 +83,8 @@ void RenderButton::styleDidChange(StyleDifference diff, const RenderStyle* oldSt { RenderBlock::styleDidChange(diff, oldStyle); + if (m_buttonText) + m_buttonText->setStyle(style()); if (m_inner) // RenderBlock handled updating the anonymous block's style. setupInnerStyle(m_inner->style()); @@ -105,6 +108,39 @@ void RenderButton::setupInnerStyle(RenderStyle* innerStyle) innerStyle->setBoxOrient(style()->boxOrient()); } +void RenderButton::updateFromElement() +{ + // If we're an input element, we may need to change our button text. + if (node()->hasTagName(inputTag)) { + HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); + String value = input->valueWithDefault(); + setText(value); + } +} + +void RenderButton::setText(const String& str) +{ + if (str.isEmpty()) { + if (m_buttonText) { + m_buttonText->destroy(); + m_buttonText = 0; + } + } else { + if (m_buttonText) + m_buttonText->setText(str.impl()); + else { + m_buttonText = new (renderArena()) RenderTextFragment(document(), str.impl()); + m_buttonText->setStyle(style()); + addChild(m_buttonText); + } + } +} + +String RenderButton::text() const +{ + return m_buttonText ? m_buttonText->text() : 0; +} + bool RenderButton::canHaveGeneratedChildren() const { // Input elements can't have generated children, but button elements can. We'll diff --git a/Source/WebCore/rendering/RenderButton.h b/Source/WebCore/rendering/RenderButton.h index 9dde45392..5be62b012 100644 --- a/Source/WebCore/rendering/RenderButton.h +++ b/Source/WebCore/rendering/RenderButton.h @@ -48,6 +48,7 @@ public: virtual bool createsAnonymousWrapper() const { return true; } void setupInnerStyle(RenderStyle*); + virtual void updateFromElement(); virtual void updateBeforeAfterContent(PseudoId); @@ -55,6 +56,9 @@ public: virtual bool hasControlClip() const { return true; } virtual LayoutRect controlClipRect(const LayoutPoint&) const; + void setText(const String&); + String text() const; + private: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -65,7 +69,9 @@ private: void timerFired(Timer<RenderButton>*); + RenderTextFragment* m_buttonText; RenderBlock* m_inner; + OwnPtr<Timer<RenderButton> > m_timer; bool m_default; }; diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index a49544df1..75986335e 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -154,6 +154,7 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_indirectCompositingReason(NoIndirectCompositingReason) #endif , m_containsDirtyOverlayScrollbars(false) + , m_updatingMarqueePosition(false) #if !ASSERT_DISABLED , m_layerListMutationAllowed(true) #endif @@ -435,8 +436,13 @@ void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerP #endif // With all our children positioned, now update our marquee if we need to. - if (m_marquee) + if (m_marquee) { + // FIXME: would like to use TemporaryChange<> but it doesn't work with bitfields. + bool oldUpdatingMarqueePosition = m_updatingMarqueePosition; + m_updatingMarqueePosition = true; m_marquee->updateMarqueePosition(); + m_updatingMarqueePosition = oldUpdatingMarqueePosition; + } if (offsetFromRoot) *offsetFromRoot = oldOffsetFromRoot; @@ -542,8 +548,12 @@ void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrol // of an object, thus RenderReplica will still repaint itself properly as the layer position was // updated above. - if (m_marquee) + if (m_marquee) { + bool oldUpdatingMarqueePosition = m_updatingMarqueePosition; + m_updatingMarqueePosition = true; m_marquee->updateMarqueePosition(); + m_updatingMarqueePosition = oldUpdatingMarqueePosition; + } } #if ENABLE(CSS_COMPOSITING) @@ -1717,7 +1727,13 @@ void RenderLayer::scrollTo(int x, int y) view->updateWidgetPositions(); } - updateCompositingLayersAfterScroll(); + if (!m_updatingMarqueePosition) { + // Avoid updating compositing layers if, higher on the stack, we're already updating layer + // positions. Updating layer positions requires a full walk of up-to-date RenderLayers, and + // in this case we're still updating their positions; we'll update compositing layers later + // when that completes. + updateCompositingLayersAfterScroll(); + } RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); Frame* frame = renderer()->frame(); @@ -3114,12 +3130,15 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co updateLayerListsIfNeeded(); // Apply clip-path to context. + bool hasClipPath = false; RenderStyle* style = renderer()->style(); if (renderer()->hasClipPath() && !context->paintingDisabled() && style) { ASSERT(style->clipPath()); if (style->clipPath()->getOperationType() == ClipPathOperation::SHAPE) { + hasClipPath = true; + context->save(); ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath()); - transparencyLayerContext->clipPath(clipPath->path(calculateLayerBounds(this, rootLayer, 0)), clipPath->windRule()); + context->clipPath(clipPath->path(calculateLayerBounds(this, rootLayer, 0)), clipPath->windRule()); } } @@ -3289,6 +3308,9 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co context->restore(); m_usedTransparency = false; } + + if (hasClipPath) + context->restore(); } void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, GraphicsContext* context, diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 8e026833d..970b1643e 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -938,6 +938,8 @@ protected: #endif bool m_containsDirtyOverlayScrollbars : 1; + bool m_updatingMarqueePosition : 1; + #if !ASSERT_DISABLED bool m_layerListMutationAllowed : 1; #endif diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp index 7a2439779..079ce429c 100644 --- a/Source/WebCore/rendering/RenderListBox.cpp +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -173,6 +173,18 @@ void RenderListBox::selectionChanged() void RenderListBox::layout() { RenderBlock::layout(); + + if (m_vBar) { + bool enabled = numVisibleItems() < numItems(); + m_vBar->setEnabled(enabled); + m_vBar->setSteps(1, max(1, numVisibleItems() - 1), itemHeight()); + m_vBar->setProportion(numVisibleItems(), numItems()); + if (!enabled) { + scrollToOffsetWithoutAnimation(VerticalScrollbar, 0); + m_indexOffset = 0; + } + } + if (m_scrollToRevealSelectionAfterLayout) { LayoutStateDisabler layoutStateDisabler(view()); scrollToRevealSelection(); @@ -250,25 +262,10 @@ LayoutUnit RenderListBox::listHeight() const return itemHeight() * numItems() - rowSpacing; } -void RenderListBox::updateLogicalHeight() +void RenderListBox::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const { - int toAdd = borderAndPaddingHeight(); - - int itemHeight = RenderListBox::itemHeight(); - setHeight(itemHeight * size() - rowSpacing + toAdd); - - RenderBlock::updateLogicalHeight(); - - if (m_vBar) { - bool enabled = numVisibleItems() < numItems(); - m_vBar->setEnabled(enabled); - m_vBar->setSteps(1, max(1, numVisibleItems() - 1), itemHeight); - m_vBar->setProportion(numVisibleItems(), numItems()); - if (!enabled) { - scrollToOffsetWithoutAnimation(VerticalScrollbar, 0); - m_indexOffset = 0; - } - } + LayoutUnit height = itemHeight() * size() - rowSpacing + borderAndPaddingHeight(); + RenderBox::computeLogicalHeight(height, logicalTop, computedValues); } LayoutUnit RenderListBox::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h index d259e767c..e936dc2ce 100644 --- a/Source/WebCore/rendering/RenderListBox.h +++ b/Source/WebCore/rendering/RenderListBox.h @@ -77,7 +77,7 @@ private: virtual void computePreferredLogicalWidths(); virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; - virtual void updateLogicalHeight() OVERRIDE; + virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; virtual void layout(); diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index 3f3849f62..0b10b69dc 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -724,7 +724,7 @@ public: // Build an array of quads in absolute coords for line boxes virtual void absoluteQuads(Vector<FloatQuad>&, bool* /*wasFixed*/ = 0) const { } - void absoluteFocusRingQuads(Vector<FloatQuad>&); + virtual void absoluteFocusRingQuads(Vector<FloatQuad>&); static FloatRect absoluteBoundingBoxRectForRange(const Range*); diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index 7761fc1e1..6aeb4d92d 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -1268,6 +1268,7 @@ void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, // Dirty all text boxes that include characters in between offset and offset+len. for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) { + // FIXME: This shouldn't rely on the end of a dirty line box. See https://bugs.webkit.org/show_bug.cgi?id=97264 // Text run is entirely before the affected range. if (curr->end() < offset) continue; diff --git a/Source/WebCore/rendering/TextAutosizer.cpp b/Source/WebCore/rendering/TextAutosizer.cpp index c4503a13b..304bdb31c 100644 --- a/Source/WebCore/rendering/TextAutosizer.cpp +++ b/Source/WebCore/rendering/TextAutosizer.cpp @@ -35,6 +35,11 @@ namespace WebCore { +struct TextAutosizingWindowInfo { + IntSize windowSize; + IntSize minLayoutSize; +}; + TextAutosizer::TextAutosizer(Document* document) : m_document(document) { @@ -53,36 +58,68 @@ bool TextAutosizer::processSubtree(RenderObject* layoutRoot) Frame* mainFrame = m_document->page()->mainFrame(); + TextAutosizingWindowInfo windowInfo; + // Window area, in logical (density-independent) pixels. - IntSize windowSize = m_document->settings()->textAutosizingWindowSizeOverride(); - if (windowSize.isEmpty()) { + windowInfo.windowSize = m_document->settings()->textAutosizingWindowSizeOverride(); + if (windowInfo.windowSize.isEmpty()) { bool includeScrollbars = !InspectorInstrumentation::shouldApplyScreenWidthOverride(mainFrame); - windowSize = mainFrame->view()->visibleContentRect(includeScrollbars).size(); // FIXME: Check that this is always in logical (density-independent) pixels (see wkbug.com/87440). + windowInfo.windowSize = mainFrame->view()->visibleContentRect(includeScrollbars).size(); // FIXME: Check that this is always in logical (density-independent) pixels (see wkbug.com/87440). } // Largest area of block that can be visible at once (assuming the main // frame doesn't get scaled to less than overview scale), in CSS pixels. - IntSize minLayoutSize = mainFrame->view()->layoutSize(); + windowInfo.minLayoutSize = mainFrame->view()->layoutSize(); for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->parent()) { if (!frame->view()->isInChildFrameWithFrameFlattening()) - minLayoutSize = minLayoutSize.shrunkTo(frame->view()->layoutSize()); + windowInfo.minLayoutSize = windowInfo.minLayoutSize.shrunkTo(frame->view()->layoutSize()); } - for (RenderObject* descendant = layoutRoot->nextInPreOrder(layoutRoot); descendant; descendant = descendant->nextInPreOrder(layoutRoot)) { - if (isNotAnAutosizingContainer(descendant)) - continue; - processBox(toRenderBox(descendant), windowSize, minLayoutSize); - } + // The layoutRoot could be neither a container nor a cluster, so walk up the tree till we find each of these. + RenderBlock* container = layoutRoot->isRenderBlock() ? toRenderBlock(layoutRoot) : layoutRoot->containingBlock(); + while (container && !isAutosizingContainer(container)) + container = container->containingBlock(); + + RenderBlock* cluster = container; + while (cluster && (!isAutosizingContainer(cluster) || !isAutosizingCluster(cluster))) + cluster = cluster->containingBlock(); + processCluster(cluster, container, layoutRoot, windowInfo); return true; } -static bool contentHeightIsConstrained(const RenderBox* box) +void TextAutosizer::processCluster(RenderBlock* cluster, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo) +{ + ASSERT(isAutosizingCluster(cluster)); + + // FIXME: Many pages set a max-width on their content. So especially for the RenderView, + // instead of just taking the width of |cluster| we should find the lowest common ancestor of + // the first and last descendant text node of the cluster (i.e. the deepest wrapper block that + // contains all the text), and use its width instead. + RenderBlock* lowestCommonAncestor = cluster; + float commonAncestorWidth = lowestCommonAncestor->contentLogicalWidth(); + + float multiplier = 1; + if (clusterShouldBeAutosized(lowestCommonAncestor, commonAncestorWidth)) { + int logicalWindowWidth = cluster->isHorizontalWritingMode() ? windowInfo.windowSize.width() : windowInfo.windowSize.height(); + int logicalLayoutWidth = cluster->isHorizontalWritingMode() ? windowInfo.minLayoutSize.width() : windowInfo.minLayoutSize.height(); + // Ignore box width in excess of the layout width, to avoid extreme multipliers. + float logicalClusterWidth = std::min<float>(commonAncestorWidth, logicalLayoutWidth); + + multiplier = logicalClusterWidth / logicalWindowWidth; + multiplier *= m_document->settings()->textAutosizingFontScaleFactor(); + multiplier = std::max(1.0f, multiplier); + } + + processContainer(multiplier, container, subtreeRoot, windowInfo); +} + +static bool contentHeightIsConstrained(const RenderBlock* container) { // FIXME: Propagate constrainedness down the tree, to avoid inefficiently walking back up from each box. // FIXME: This code needs to take into account vertical writing modes. // FIXME: Consider additional heuristics, such as ignoring fixed heights if the content is already overflowing before autosizing kicks in. - for (const RenderBox* container = box; container; container = container->containingBlock()) { + for (; container; container = container->containingBlock()) { RenderStyle* style = container->style(); if (style->overflowY() >= OSCROLL) return false; @@ -97,29 +134,28 @@ static bool contentHeightIsConstrained(const RenderBox* box) return false; } -void TextAutosizer::processBox(RenderBox* box, const IntSize& windowSize, const IntSize& layoutSize) +void TextAutosizer::processContainer(float multiplier, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo& windowInfo) { - if (contentHeightIsConstrained(box)) - return; - - int logicalWindowWidth = box->isHorizontalWritingMode() ? windowSize.width() : windowSize.height(); - int logicalLayoutWidth = box->isHorizontalWritingMode() ? layoutSize.width() : layoutSize.height(); - // Ignore box width in excess of the layout width, to avoid extreme multipliers. - float logicalBoxWidth = std::min<float>(box->logicalWidth(), logicalLayoutWidth); + ASSERT(isAutosizingContainer(container)); - float multiplier = logicalBoxWidth / logicalWindowWidth; - multiplier *= m_document->settings()->textAutosizingFontScaleFactor(); + float localMultiplier = contentHeightIsConstrained(container) ? 1 : multiplier; - if (multiplier < 1) - return; - RenderObject* descendant = nextInPreOrderMatchingFilter(box, box, isNotAnAutosizingContainer); + RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(subtreeRoot, subtreeRoot); while (descendant) { if (descendant->isText()) { - setMultiplier(descendant, multiplier); - setMultiplier(descendant->parent(), multiplier); // Parent does line spacing. + if (localMultiplier != descendant->style()->textAutosizingMultiplier()) { + setMultiplier(descendant, localMultiplier); + setMultiplier(descendant->parent(), localMultiplier); // Parent does line spacing. + } // FIXME: Increase list marker size proportionately. + } else if (isAutosizingContainer(descendant)) { + RenderBlock* descendantBlock = toRenderBlock(descendant); + if (isAutosizingCluster(descendantBlock)) + processCluster(descendantBlock, descendantBlock, descendantBlock, windowInfo); + else + processContainer(multiplier, descendantBlock, descendantBlock, windowInfo); } - descendant = nextInPreOrderMatchingFilter(descendant, box, isNotAnAutosizingContainer); + descendant = nextInPreOrderSkippingDescendantsOfContainers(descendant, subtreeRoot); } } @@ -158,28 +194,104 @@ float TextAutosizer::computeAutosizedFontSize(float specifiedSize, float multipl return computedSize; } -bool TextAutosizer::isNotAnAutosizingContainer(const RenderObject* renderer) +bool TextAutosizer::isAutosizingContainer(const RenderObject* renderer) { - // "Autosizing containers" are the smallest unit for which we can enable/disable - // Text Autosizing. A uniform text size multiplier is enforced within them. - // - Must be RenderBoxes since they need a well-defined logicalWidth(). + // "Autosizing containers" are the smallest unit for which we can + // enable/disable Text Autosizing. // - Must not be inline, as different multipliers on one line looks terrible. // - Must not be list items, as items in the same list should look consistent. - return !renderer->isBox() || renderer->isInline() || renderer->isListItem(); + return renderer->isRenderBlock() && !renderer->isInline() && !renderer->isListItem(); +} + +bool TextAutosizer::isAutosizingCluster(const RenderBlock* renderer) +{ + // "Autosizing clusters" are special autosizing containers within which we + // want to enforce a uniform text size multiplier, in the hopes of making + // the major sections of the page look internally consistent. + // All their descendents (including other autosizing containers) must share + // the same multiplier, except for subtrees which are themselves clusters, + // and some of their descendent containers might not be autosized at all + // (for example if their height is constrained). + // Additionally, clusterShouldBeAutosized requires each cluster to contain a + // minimum amount of text, without which it won't be autosized. + // + // Clusters are chosen using very similar criteria to CSS flow roots, aka + // block formatting contexts (http://w3.org/TR/css3-box/#flow-root), since + // flow roots correspond to box containers that behave somewhat + // independently from their parent (for example they don't overlap floats). + // The definition of a flow flow root also conveniently includes most of the + // ways that a box and its children can have significantly different width + // from the box's parent (we want to avoid having significantly different + // width blocks within a cluster, since the narrower blocks would end up + // larger than would otherwise be necessary). + ASSERT(isAutosizingContainer(renderer)); + + return renderer->isRenderView() + || renderer->isFloating() + || renderer->isOutOfFlowPositioned() + || renderer->isTableCell() + || renderer->isTableCaption() + || renderer->isFlexibleBoxIncludingDeprecated() + || renderer->hasColumns() + || renderer->style()->overflowX() != OVISIBLE + || renderer->style()->overflowY() != OVISIBLE + || renderer->containingBlock()->isHorizontalWritingMode() != renderer->isHorizontalWritingMode(); + // FIXME: Tables need special handling to multiply all their columns by + // the same amount even if they're different widths; so do hasColumns() + // renderers, and probably flexboxes... +} + +bool TextAutosizer::clusterShouldBeAutosized(const RenderBlock* lowestCommonAncestor, float commonAncestorWidth) +{ + // Don't autosize clusters that contain less than 4 lines of text (in + // practice less lines are required, since measureDescendantTextWidth + // assumes that characters are 1em wide, but most characters are narrower + // than that, so we're overestimating their contribution to the linecount). + // + // This is to reduce the likelihood of autosizing things like headers and + // footers, which can be quite visually distracting. The rationale is that + // if a cluster contains very few lines of text then it's ok to have to zoom + // in and pan from side to side to read each line, since if there are very + // few lines of text you'll only need to pan across once or twice. + const float minLinesOfText = 4; + float minTextWidth = commonAncestorWidth * minLinesOfText; + float textWidth = 0; + measureDescendantTextWidth(lowestCommonAncestor, minTextWidth, textWidth); + if (textWidth >= minTextWidth) + return true; + return false; +} + +void TextAutosizer::measureDescendantTextWidth(const RenderBlock* container, float minTextWidth, float& textWidth) +{ + bool skipLocalText = contentHeightIsConstrained(container); + + RenderObject* descendant = nextInPreOrderSkippingDescendantsOfContainers(container, container); + while (descendant) { + if (!skipLocalText && descendant->isText()) { + textWidth += toRenderText(descendant)->renderedTextLength() * descendant->style()->specifiedFontSize(); + } else if (isAutosizingContainer(descendant)) { + RenderBlock* descendantBlock = toRenderBlock(descendant); + if (!isAutosizingCluster(descendantBlock)) + measureDescendantTextWidth(descendantBlock, minTextWidth, textWidth); + } + if (textWidth >= minTextWidth) + return; + descendant = nextInPreOrderSkippingDescendantsOfContainers(descendant, container); + } } -RenderObject* TextAutosizer::nextInPreOrderMatchingFilter(RenderObject* current, const RenderObject* stayWithin, RenderObjectFilterFunctor filter) +RenderObject* TextAutosizer::nextInPreOrderSkippingDescendantsOfContainers(const RenderObject* current, const RenderObject* stayWithin) { - for (RenderObject* child = current->firstChild(); child; child = child->nextSibling()) - if (filter(child)) + if (current == stayWithin || !isAutosizingContainer(current)) + for (RenderObject* child = current->firstChild(); child; child = child->nextSibling()) return child; for (const RenderObject* ancestor = current; ancestor; ancestor = ancestor->parent()) { if (ancestor == stayWithin) return 0; for (RenderObject* sibling = ancestor->nextSibling(); sibling; sibling = sibling->nextSibling()) - if (filter(sibling)) - return sibling; + return sibling; } return 0; diff --git a/Source/WebCore/rendering/TextAutosizer.h b/Source/WebCore/rendering/TextAutosizer.h index ae9fd8363..2e2e70e6b 100644 --- a/Source/WebCore/rendering/TextAutosizer.h +++ b/Source/WebCore/rendering/TextAutosizer.h @@ -36,10 +36,11 @@ namespace WebCore { class Document; -class RenderBox; +class RenderBlock; class RenderObject; class RenderStyle; class RenderText; +struct TextAutosizingWindowInfo; class TextAutosizer { WTF_MAKE_NONCOPYABLE(TextAutosizer); @@ -56,14 +57,19 @@ public: private: explicit TextAutosizer(Document*); - void processBox(RenderBox*, const IntSize& windowSize, const IntSize& layoutSize); + void processCluster(RenderBlock* cluster, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&); + void processContainer(float multiplier, RenderBlock* container, RenderObject* subtreeRoot, const TextAutosizingWindowInfo&); + void setMultiplier(RenderObject*, float); - static bool isNotAnAutosizingContainer(const RenderObject*); + static bool isAutosizingContainer(const RenderObject*); + static bool isAutosizingCluster(const RenderBlock*); + + static bool clusterShouldBeAutosized(const RenderBlock* lowestCommonAncestor, float commonAncestorWidth); + static void measureDescendantTextWidth(const RenderBlock* container, float minTextWidth, float& textWidth); - typedef bool (*RenderObjectFilterFunctor)(const RenderObject*); - // Use to traverse the tree of descendants, excluding any subtrees within that whose root doesn't pass the filter. - static RenderObject* nextInPreOrderMatchingFilter(RenderObject* current, const RenderObject* stayWithin, RenderObjectFilterFunctor); + // Use to traverse the tree of descendants, excluding descendants of containers (but returning the containers themselves). + static RenderObject* nextInPreOrderSkippingDescendantsOfContainers(const RenderObject* current, const RenderObject* stayWithin); Document* m_document; }; diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp index d44a93da4..56372b49f 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -164,6 +164,13 @@ static bool isGraphicsElement(RenderObject* renderer) return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag); } +// The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads +// returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds. +void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) +{ + quads.append(localToAbsoluteQuad(FloatQuad(repaintRectInLocalCoordinates()))); +} + bool RenderSVGModelObject::checkIntersection(RenderObject* renderer, const FloatRect& rect) { if (!renderer || renderer->style()->pointerEvents() == PE_NONE) diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h index a99dd9da7..b83ca0fcb 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -72,6 +72,7 @@ protected: private: // This method should never be called, SVG uses a different nodeAtPoint method bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual void absoluteFocusRingQuads(Vector<FloatQuad>&); }; } |
