Commit 344d1d48 authored by wkorman's avatar wkorman Committed by Commit bot

Calculate correct cull rect for SVG inline text boxes.

Cull rects were larger than needed when text was selected.

Identified while investigating test failure of:

svg/text/text-selection-align-06-b.svg

as part of http://crrev.com/2073563002 for crbug.com/616600, though
fixing these did not actually fix any issues for that patch or bug.

Reland of http://crrev.com/2137753002 with updated test to
approximate expected rects to allow for minor font metrics differences
across platforms. Notably, previous patch failed on Android Nexus 4
due to 1 - 2 pixel deltas.

BUG=627233
TBR=pdr

Review-Url: https://codereview.chromium.org/2151323004
Cr-Commit-Position: refs/heads/master@{#405920}
parent fe47448d
...@@ -4189,6 +4189,7 @@ ...@@ -4189,6 +4189,7 @@
'paint/PaintLayerPainterTest.cpp', 'paint/PaintLayerPainterTest.cpp',
'paint/PaintPropertyTreeBuilderTest.cpp', 'paint/PaintPropertyTreeBuilderTest.cpp',
'paint/StubChromeClientForSPv2.h', 'paint/StubChromeClientForSPv2.h',
'paint/SVGInlineTextBoxPainterTest.cpp',
'paint/TableCellPainterTest.cpp', 'paint/TableCellPainterTest.cpp',
'paint/TextPainterTest.cpp', 'paint/TextPainterTest.cpp',
'paint/VideoPainterTest.cpp', 'paint/VideoPainterTest.cpp',
......
...@@ -45,7 +45,7 @@ class Node; ...@@ -45,7 +45,7 @@ class Node;
class Range; class Range;
class TreeScope; class TreeScope;
class DOMSelection final : public GarbageCollected<DOMSelection>, public ScriptWrappable, public DOMWindowProperty { class CORE_EXPORT DOMSelection final : public GarbageCollected<DOMSelection>, public ScriptWrappable, public DOMWindowProperty {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(DOMSelection); USING_GARBAGE_COLLECTED_MIXIN(DOMSelection);
public: public:
......
...@@ -45,13 +45,12 @@ FloatRect SVGInlineTextBoxPainter::boundsForDrawingRecorder( ...@@ -45,13 +45,12 @@ FloatRect SVGInlineTextBoxPainter::boundsForDrawingRecorder(
// computation in SVGInlineTextBox::calculateBoundaries, and the fact that vertical (etc) // computation in SVGInlineTextBox::calculateBoundaries, and the fact that vertical (etc)
// layouts are handled by SVGTextLayoutEngine. // layouts are handled by SVGTextLayoutEngine.
LayoutRect bounds( LayoutRect bounds(
m_svgInlineTextBox.topLeft(), LayoutPoint(m_svgInlineTextBox.topLeft() + paintOffset),
LayoutSize(m_svgInlineTextBox.logicalWidth(), m_svgInlineTextBox.logicalHeight())); LayoutSize(m_svgInlineTextBox.logicalWidth(), m_svgInlineTextBox.logicalHeight()));
if (includeSelectionRect) { if (includeSelectionRect) {
bounds.unite(m_svgInlineTextBox.localSelectionRect( bounds.unite(m_svgInlineTextBox.localSelectionRect(
m_svgInlineTextBox.start(), m_svgInlineTextBox.start() + m_svgInlineTextBox.len())); m_svgInlineTextBox.start(), m_svgInlineTextBox.start() + m_svgInlineTextBox.len()));
} }
bounds.moveBy(paintOffset);
return FloatRect(bounds); return FloatRect(bounds);
} }
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/paint/SVGInlineTextBoxPainter.h"
#include "core/dom/Document.h"
#include "core/dom/Range.h"
#include "core/editing/DOMSelection.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/layout/LayoutTestHelper.h"
#include "core/layout/line/InlineTextBox.h"
#include "core/layout/svg/LayoutSVGInlineText.h"
#include "core/layout/svg/LayoutSVGText.h"
#include "core/paint/PaintLayer.h"
#include "platform/graphics/GraphicsLayer.h"
#include "platform/graphics/paint/DisplayItemList.h"
#include "platform/graphics/paint/DrawingDisplayItem.h"
#include "platform/graphics/paint/PaintController.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace {
class SVGInlineTextBoxPainterTest : public RenderingTest {
public:
const DrawingDisplayItem* getDrawingForSVGTextById(const char* elementName)
{
// Look up the inline text box that serves as the display item client for the painted text.
LayoutSVGText* targetSVGText = toLayoutSVGText(
document().getElementById(AtomicString(elementName))->layoutObject());
LayoutSVGInlineText* targetInlineText = targetSVGText->descendantTextNodes()[0];
const DisplayItemClient* targetClient = static_cast<const DisplayItemClient*>(targetInlineText->firstTextBox());
// Find the appropriate drawing in the display item list.
const DisplayItemList& displayItemList = rootPaintController().getDisplayItemList();
for (size_t i = 0; i < displayItemList.size(); i++) {
if (displayItemList[i].client() == *targetClient)
return static_cast<const DrawingDisplayItem*>(&displayItemList[i]);
}
return nullptr;
}
void selectAllText()
{
Range* range = document().createRange();
range->selectNode(document().documentElement());
LocalDOMWindow* window = document().domWindow();
DOMSelection* selection = window->getSelection();
selection->removeAllRanges();
selection->addRange(range);
}
private:
PaintController& rootPaintController()
{
return document().view()->layoutView()->layer()->graphicsLayerBacking()->getPaintController();
}
void SetUp() override
{
RenderingTest::SetUp();
enableCompositing();
}
};
static void assertTextDrawingEquals(const DrawingDisplayItem* drawingDisplayItem, const char* str)
{
ASSERT_EQ(str, static_cast<const InlineTextBox*>(&drawingDisplayItem->client())->text());
}
const static int kAllowedPixelDelta = 4;
static void assertCullRectEquals(const DrawingDisplayItem* drawingDisplayItem, const IntRect& expectedRect)
{
// Text metrics can vary slightly across platforms, so we allow for a small pixel difference.
IntRect outerRect(expectedRect);
int delta = kAllowedPixelDelta / 2;
outerRect.expand(delta, delta);
IntRect innerRect(expectedRect);
// Rect contains is inclusive of edge, so shrink by one extra pixel.
innerRect.contract(delta + 1, delta + 1);
IntRect actualRect(IntRect(drawingDisplayItem->picture()->cullRect()));
ASSERT_TRUE(outerRect.contains(actualRect) && !innerRect.contains(actualRect))
<< "Cull rect not approximately equal [expected=("
<< expectedRect.x() << "," << expectedRect.y() << " " << expectedRect.width() << "x" << expectedRect.height() << "), actual=("
<< actualRect.x() << "," << actualRect.y() << " " << actualRect.width() << "x" << actualRect.height() << ")].";
}
TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_DefaultWritingMode)
{
setBodyInnerHTML(
"<svg width='400px' height='400px' font-family='Arial' font-size='30'>"
"<text id='target' x='50' y='30'>x</text>"
"</svg>");
document().view()->updateAllLifecyclePhases();
const DrawingDisplayItem* drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(50, 3, 15, 33));
selectAllText();
document().view()->updateAllLifecyclePhases();
drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(50, 3, 15, 33));
}
TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_WritingModeTopToBottom)
{
setBodyInnerHTML(
"<svg width='400px' height='400px' font-family='Arial' font-size='30'>"
"<text id='target' x='50' y='30' writing-mode='tb'>x</text>"
"</svg>");
document().view()->updateAllLifecyclePhases();
const DrawingDisplayItem* drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(33, 30, 34, 15));
selectAllText();
document().view()->updateAllLifecyclePhases();
// The selection rect is one pixel taller due to sub-pixel difference
// between the text bounds and selection bounds in combination with use of
// enclosingIntRect() in SVGInlineTextBox::localSelectionRect().
drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(33, 30, 34, 16));
}
} // namespace
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment