Skip to content

Commit

Permalink
Include any text shadow bounds in SVG text cull rect.
Browse files Browse the repository at this point in the history
BUG=628414

Review-Url: https://codereview.chromium.org/2162033003
Cr-Commit-Position: refs/heads/master@{#406612}
  • Loading branch information
shaper authored and Commit bot committed Jul 20, 2016
1 parent 058b59c commit 378e044
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 30 deletions.
21 changes: 12 additions & 9 deletions third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,23 @@ bool SVGInlineTextBoxPainter::shouldPaintSelection(const PaintInfo& paintInfo) c
return !paintInfo.isPrinting() && m_svgInlineTextBox.getSelectionState() != SelectionNone;
}

static bool hasShadow(const PaintInfo& paintInfo, const ComputedStyle& style)
{
// Text shadows are disabled when printing. http://crbug.com/258321
return style.textShadow() && !paintInfo.isPrinting();
}

FloatRect SVGInlineTextBoxPainter::boundsForDrawingRecorder(
const LayoutPoint& paintOffset, bool includeSelectionRect) const
const PaintInfo& paintInfo, const ComputedStyle& style, const LayoutPoint& paintOffset, bool includeSelectionRect) const
{
// We compute the paint rect with what looks like the logical values, to match the
// computation in SVGInlineTextBox::calculateBoundaries, and the fact that vertical (etc)
// layouts are handled by SVGTextLayoutEngine.
LayoutRect bounds(
LayoutPoint(m_svgInlineTextBox.topLeft() + paintOffset),
LayoutSize(m_svgInlineTextBox.logicalWidth(), m_svgInlineTextBox.logicalHeight()));
if (hasShadow(paintInfo, style))
bounds.expand(style.textShadow()->rectOutsetsIncludingOriginal());
if (includeSelectionRect) {
bounds.unite(m_svgInlineTextBox.localSelectionRect(
m_svgInlineTextBox.start(), m_svgInlineTextBox.start() + m_svgInlineTextBox.len()));
Expand Down Expand Up @@ -81,7 +89,7 @@ void SVGInlineTextBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoin
bool includeSelectionRect = paintInfo.phase != PaintPhaseSelection
&& (haveSelection || InlineTextBoxPainter::paintsMarkerHighlights(textLayoutObject));
DrawingRecorder recorder(paintInfo.context, m_svgInlineTextBox, displayItemType,
boundsForDrawingRecorder(paintOffset, includeSelectionRect));
boundsForDrawingRecorder(paintInfo, style, paintOffset, includeSelectionRect));
InlineTextBoxPainter(m_svgInlineTextBox).paintDocumentMarkers(
paintInfo, paintOffset, style,
textLayoutObject.scaledFont(), DocumentMarkerPaintPhase::Background);
Expand Down Expand Up @@ -314,11 +322,6 @@ bool SVGInlineTextBoxPainter::setupTextPaint(const PaintInfo& paintInfo, const C
float scalingFactor = textLayoutObject.scalingFactor();
ASSERT(scalingFactor);

const ShadowList* shadowList = style.textShadow();

// Text shadows are disabled when printing. http://crbug.com/258321
bool hasShadow = shadowList && !paintInfo.isPrinting();

AffineTransform paintServerTransform;
const AffineTransform* additionalPaintServerTransform = 0;

Expand All @@ -332,8 +335,8 @@ bool SVGInlineTextBoxPainter::setupTextPaint(const PaintInfo& paintInfo, const C
return false;
paint.setAntiAlias(true);

if (hasShadow) {
std::unique_ptr<DrawLooperBuilder> drawLooperBuilder = shadowList->createDrawLooper(DrawLooperBuilder::ShadowRespectsAlpha, style.visitedDependentColor(CSSPropertyColor));
if (hasShadow(paintInfo, style)) {
std::unique_ptr<DrawLooperBuilder> drawLooperBuilder = style.textShadow()->createDrawLooper(DrawLooperBuilder::ShadowRespectsAlpha, style.visitedDependentColor(CSSPropertyColor));
paint.setLooper(toSkSp(drawLooperBuilder->detachDrawLooper()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class SVGInlineTextBoxPainter {

private:
bool shouldPaintSelection(const PaintInfo&) const;
FloatRect boundsForDrawingRecorder(const LayoutPoint&, bool includeSelectionRect) const;
FloatRect boundsForDrawingRecorder(const PaintInfo&, const ComputedStyle&, const LayoutPoint&, bool includeSelectionRect) const;
void paintTextFragments(const PaintInfo&, LayoutObject&);
void paintDecoration(const PaintInfo&, TextDecoration, const SVGTextFragment&);
bool setupTextPaint(const PaintInfo&, const ComputedStyle&, LayoutSVGResourceMode, SkPaint&);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,25 @@ static void assertTextDrawingEquals(const DrawingDisplayItem* drawingDisplayItem
ASSERT_EQ(str, static_cast<const InlineTextBox*>(&drawingDisplayItem->client())->text());
}

const static int kAllowedPixelDelta = 8;
bool ApproximatelyEqual(int a, int b, int delta)
{
return abs(a - b) <= delta;
}

const static int kPixelDelta = 4;

#define EXPECT_RECT_EQ(expected, actual) \
do { \
const FloatRect& actualRect = actual; \
EXPECT_TRUE(ApproximatelyEqual(expected.x(), actualRect.x(), kPixelDelta)) << "actual: " << actualRect.x() << ", expected: " << expected.x(); \
EXPECT_TRUE(ApproximatelyEqual(expected.y(), actualRect.y(), kPixelDelta)) << "actual: " << actualRect.y() << ", expected: " << expected.y(); \
EXPECT_TRUE(ApproximatelyEqual(expected.width(), actualRect.width(), kPixelDelta)) << "actual: " << actualRect.width() << ", expected: " << expected.width(); \
EXPECT_TRUE(ApproximatelyEqual(expected.height(), actualRect.height(), kPixelDelta)) << "actual: " << actualRect.height() << ", expected: " << expected.height(); \
} while (false)

static void assertCullRectEquals(const DrawingDisplayItem* drawingDisplayItem, const IntRect& expectedRect)
static IntRect cullRectFromDrawing(const DrawingDisplayItem& drawingDisplayItem)
{
// Text metrics can vary slightly across platforms, so we allow for a small pixel difference.
IntRect outerRect(expectedRect);
int delta = kAllowedPixelDelta / 2;
outerRect.expand(IntRectOutsets(delta, delta, delta, delta));
IntRect innerRect(expectedRect);
// Rect contains is inclusive of edge, so shrink by one extra pixel.
int contractDelta = -delta - 1;
innerRect.expand(IntRectOutsets(contractDelta, contractDelta, contractDelta, contractDelta));

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() << ")].";
return IntRect(drawingDisplayItem.picture()->cullRect());
}

TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_DefaultWritingMode)
Expand All @@ -101,14 +102,14 @@ TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_DefaultWritingMode)

const DrawingDisplayItem* drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(50, 3, 15, 33));
EXPECT_RECT_EQ(IntRect(50, 3, 15, 33), cullRectFromDrawing(*drawingDisplayItem));

selectAllText();
document().view()->updateAllLifecyclePhases();

drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(50, 3, 15, 33));
EXPECT_RECT_EQ(IntRect(50, 3, 15, 33), cullRectFromDrawing(*drawingDisplayItem));
}

TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_WritingModeTopToBottom)
Expand All @@ -121,7 +122,7 @@ TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_WritingModeTopToBottom)

const DrawingDisplayItem* drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(33, 30, 34, 15));
EXPECT_RECT_EQ(IntRect(33, 30, 34, 15), cullRectFromDrawing(*drawingDisplayItem));

selectAllText();
document().view()->updateAllLifecyclePhases();
Expand All @@ -131,7 +132,20 @@ TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_WritingModeTopToBottom)
// enclosingIntRect() in SVGInlineTextBox::localSelectionRect().
drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
assertCullRectEquals(drawingDisplayItem, IntRect(33, 30, 34, 16));
EXPECT_RECT_EQ(IntRect(33, 30, 34, 16), cullRectFromDrawing(*drawingDisplayItem));
}

TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_TextShadow)
{
setBodyInnerHTML(
"<svg width='400px' height='400px' font-family='Arial' font-size='30'>"
"<text id='target' x='50' y='30' style='text-shadow: 200px 200px 5px red'>x</text>"
"</svg>");
document().view()->updateAllLifecyclePhases();

const DrawingDisplayItem* drawingDisplayItem = getDrawingForSVGTextById("target");
assertTextDrawingEquals(drawingDisplayItem, "x");
EXPECT_RECT_EQ(IntRect(50, 3, 220, 238), cullRectFromDrawing(*drawingDisplayItem));
}

} // namespace
Expand Down

0 comments on commit 378e044

Please sign in to comment.