summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering')
-rw-r--r--Source/WebCore/rendering/FilterEffectRenderer.h2
-rw-r--r--Source/WebCore/rendering/InlineBox.h2
-rw-r--r--Source/WebCore/rendering/InlineTextBox.cpp9
-rw-r--r--Source/WebCore/rendering/InlineTextBox.h5
-rwxr-xr-xSource/WebCore/rendering/RenderBlockLineLayout.cpp8
-rw-r--r--Source/WebCore/rendering/RenderBox.h2
-rw-r--r--Source/WebCore/rendering/RenderButton.cpp36
-rw-r--r--Source/WebCore/rendering/RenderButton.h6
-rw-r--r--Source/WebCore/rendering/RenderLayer.cpp30
-rw-r--r--Source/WebCore/rendering/RenderLayer.h2
-rw-r--r--Source/WebCore/rendering/RenderListBox.cpp33
-rw-r--r--Source/WebCore/rendering/RenderListBox.h2
-rw-r--r--Source/WebCore/rendering/RenderObject.h2
-rw-r--r--Source/WebCore/rendering/RenderText.cpp1
-rw-r--r--Source/WebCore/rendering/TextAutosizer.cpp188
-rw-r--r--Source/WebCore/rendering/TextAutosizer.h18
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGModelObject.cpp7
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGModelObject.h1
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>&);
};
}