blob: 7de53eb78014465b96b3cf101223b4e8dad157e6 [file] [log] [blame]
// Copyright 2014 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/ObjectPainter.h"
#include "core/layout/LayoutBlock.h"
#include "core/layout/LayoutInline.h"
#include "core/layout/LayoutObject.h"
#include "core/layout/LayoutTheme.h"
#include "core/paint/BoxBorderPainter.h"
#include "core/paint/LayoutObjectDrawingRecorder.h"
#include "core/paint/PaintInfo.h"
#include "core/style/BorderEdge.h"
#include "core/style/ComputedStyle.h"
#include "platform/geometry/LayoutPoint.h"
namespace blink {
namespace {
void paintSingleRectangleOutline(const PaintInfo& paintInfo,
const IntRect& rect,
const ComputedStyle& style,
const Color& color) {
ASSERT(!style.outlineStyleIsAuto());
LayoutRect inner(rect);
inner.inflate(style.outlineOffset());
LayoutRect outer(inner);
outer.inflate(style.outlineWidth());
const BorderEdge commonEdgeInfo(style.outlineWidth(), color,
style.outlineStyle());
BoxBorderPainter(style, outer, inner, commonEdgeInfo)
.paintBorder(paintInfo, outer);
}
struct OutlineEdgeInfo {
int x1;
int y1;
int x2;
int y2;
BoxSide side;
};
// Adjust length of edges if needed. Returns the width of the joint.
int adjustJoint(int outlineWidth,
OutlineEdgeInfo& edge1,
OutlineEdgeInfo& edge2) {
// A clockwise joint:
// - needs no adjustment of edge length because our edges are along the
// clockwise outer edge of the outline;
// - needs a positive adjacent joint width (required by drawLineForBoxSide).
// A counterclockwise joint:
// - needs to increase the edge length to include the joint;
// - needs a negative adjacent joint width (required by drawLineForBoxSide).
switch (edge1.side) {
case BSTop:
switch (edge2.side) {
case BSRight: // Clockwise
return outlineWidth;
case BSLeft: // Counterclockwise
edge1.x2 += outlineWidth;
edge2.y2 += outlineWidth;
return -outlineWidth;
default: // Same side or no joint.
return 0;
}
case BSRight:
switch (edge2.side) {
case BSBottom: // Clockwise
return outlineWidth;
case BSTop: // Counterclockwise
edge1.y2 += outlineWidth;
edge2.x1 -= outlineWidth;
return -outlineWidth;
default: // Same side or no joint.
return 0;
}
case BSBottom:
switch (edge2.side) {
case BSLeft: // Clockwise
return outlineWidth;
case BSRight: // Counterclockwise
edge1.x1 -= outlineWidth;
edge2.y1 -= outlineWidth;
return -outlineWidth;
default: // Same side or no joint.
return 0;
}
case BSLeft:
switch (edge2.side) {
case BSTop: // Clockwise
return outlineWidth;
case BSBottom: // Counterclockwise
edge1.y1 -= outlineWidth;
edge2.x2 += outlineWidth;
return -outlineWidth;
default: // Same side or no joint.
return 0;
}
default:
ASSERT_NOT_REACHED();
return 0;
}
}
void paintComplexOutline(GraphicsContext& graphicsContext,
const Vector<IntRect> rects,
const ComputedStyle& style,
const Color& color) {
ASSERT(!style.outlineStyleIsAuto());
// Construct a clockwise path along the outer edge of the outline.
SkRegion region;
int width = style.outlineWidth();
int outset = style.outlineOffset() + style.outlineWidth();
for (auto& r : rects) {
IntRect rect = r;
rect.inflate(outset);
region.op(rect, SkRegion::kUnion_Op);
}
SkPath path;
if (!region.getBoundaryPath(&path))
return;
Vector<OutlineEdgeInfo, 4> edges;
SkPath::Iter iter(path, false);
SkPoint points[4];
size_t count = 0;
for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Verb;
verb = iter.next(points, false)) {
if (verb != SkPath::kLine_Verb)
continue;
edges.grow(++count);
OutlineEdgeInfo& edge = edges.last();
edge.x1 = SkScalarTruncToInt(points[0].x());
edge.y1 = SkScalarTruncToInt(points[0].y());
edge.x2 = SkScalarTruncToInt(points[1].x());
edge.y2 = SkScalarTruncToInt(points[1].y());
if (edge.x1 == edge.x2) {
if (edge.y1 < edge.y2) {
edge.x1 -= width;
edge.side = BSRight;
} else {
std::swap(edge.y1, edge.y2);
edge.x2 += width;
edge.side = BSLeft;
}
} else {
ASSERT(edge.y1 == edge.y2);
if (edge.x1 < edge.x2) {
edge.y2 += width;
edge.side = BSTop;
} else {
std::swap(edge.x1, edge.x2);
edge.y1 -= width;
edge.side = BSBottom;
}
}
}
if (!count)
return;
Color outlineColor = color;
bool useTransparencyLayer = color.hasAlpha();
if (useTransparencyLayer) {
graphicsContext.beginLayer(static_cast<float>(color.alpha()) / 255);
outlineColor =
Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
}
ASSERT(count >= 4 && edges.size() == count);
int firstAdjacentWidth = adjustJoint(width, edges.last(), edges.first());
// The width of the angled part of starting and ending joint of the current
// edge.
int adjacentWidthStart = firstAdjacentWidth;
int adjacentWidthEnd;
for (size_t i = 0; i < count; ++i) {
OutlineEdgeInfo& edge = edges[i];
adjacentWidthEnd = i == count - 1 ? firstAdjacentWidth
: adjustJoint(width, edge, edges[i + 1]);
int adjacentWidth1 = adjacentWidthStart;
int adjacentWidth2 = adjacentWidthEnd;
if (edge.side == BSLeft || edge.side == BSBottom)
std::swap(adjacentWidth1, adjacentWidth2);
ObjectPainter::drawLineForBoxSide(graphicsContext, edge.x1, edge.y1,
edge.x2, edge.y2, edge.side, outlineColor,
style.outlineStyle(), adjacentWidth1,
adjacentWidth2, false);
adjacentWidthStart = adjacentWidthEnd;
}
if (useTransparencyLayer)
graphicsContext.endLayer();
}
void fillQuad(GraphicsContext& context,
const FloatPoint quad[],
const Color& color,
bool antialias) {
SkPath path;
path.moveTo(quad[0]);
path.lineTo(quad[1]);
path.lineTo(quad[2]);
path.lineTo(quad[3]);
SkPaint paint(context.fillPaint());
paint.setAntiAlias(antialias);
paint.setColor(color.rgb());
context.drawPath(path, paint);
}
} // namespace
void ObjectPainter::paintOutline(const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
ASSERT(shouldPaintSelfOutline(paintInfo.phase));
const ComputedStyle& styleToUse = m_layoutObject.styleRef();
if (!styleToUse.hasOutline() ||
styleToUse.visibility() != EVisibility::Visible)
return;
// Only paint the focus ring by hand if the theme isn't able to draw the focus
// ring.
if (styleToUse.outlineStyleIsAuto() &&
!LayoutTheme::theme().shouldDrawDefaultFocusRing(m_layoutObject))
return;
Vector<LayoutRect> outlineRects;
m_layoutObject.addOutlineRects(
outlineRects, paintOffset,
m_layoutObject.outlineRectsShouldIncludeBlockVisualOverflow());
if (outlineRects.isEmpty())
return;
if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(
paintInfo.context, m_layoutObject, paintInfo.phase))
return;
// The result rects are in coordinates of m_layoutObject's border box.
// Block flipping is not applied yet if !m_layoutObject.isBox().
if (!m_layoutObject.isBox() &&
m_layoutObject.styleRef().isFlippedBlocksWritingMode()) {
LayoutBlock* container = m_layoutObject.containingBlock();
if (container) {
m_layoutObject.localToAncestorRects(outlineRects, container, -paintOffset,
paintOffset);
if (outlineRects.isEmpty())
return;
}
}
Vector<IntRect> pixelSnappedOutlineRects;
for (auto& r : outlineRects)
pixelSnappedOutlineRects.append(pixelSnappedIntRect(r));
IntRect unitedOutlineRect = unionRectEvenIfEmpty(pixelSnappedOutlineRects);
IntRect bounds = unitedOutlineRect;
bounds.inflate(m_layoutObject.styleRef().outlineOutsetExtent());
LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutObject,
paintInfo.phase, bounds);
Color color =
m_layoutObject.resolveColor(styleToUse, CSSPropertyOutlineColor);
if (styleToUse.outlineStyleIsAuto()) {
paintInfo.context.drawFocusRing(pixelSnappedOutlineRects,
styleToUse.outlineWidth(),
styleToUse.outlineOffset(), color);
return;
}
if (unitedOutlineRect == pixelSnappedOutlineRects[0]) {
paintSingleRectangleOutline(paintInfo, unitedOutlineRect, styleToUse,
color);
return;
}
paintComplexOutline(paintInfo.context, pixelSnappedOutlineRects, styleToUse,
color);
}
void ObjectPainter::paintInlineChildrenOutlines(
const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
ASSERT(shouldPaintDescendantOutlines(paintInfo.phase));
PaintInfo paintInfoForDescendants = paintInfo.forDescendants();
for (LayoutObject* child = m_layoutObject.slowFirstChild(); child;
child = child->nextSibling()) {
if (child->isLayoutInline() &&
!toLayoutInline(child)->hasSelfPaintingLayer())
child->paint(paintInfoForDescendants, paintOffset);
}
}
void ObjectPainter::addPDFURLRectIfNeeded(const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
ASSERT(paintInfo.isPrinting());
if (m_layoutObject.isElementContinuation() || !m_layoutObject.node() ||
!m_layoutObject.node()->isLink() ||
m_layoutObject.styleRef().visibility() != EVisibility::Visible)
return;
KURL url = toElement(m_layoutObject.node())->hrefURL();
if (!url.isValid())
return;
Vector<LayoutRect> visualOverflowRects;
m_layoutObject.addElementVisualOverflowRects(visualOverflowRects,
paintOffset);
IntRect rect = pixelSnappedIntRect(unionRect(visualOverflowRects));
if (rect.isEmpty())
return;
if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(
paintInfo.context, m_layoutObject,
DisplayItem::kPrintedContentPDFURLRect))
return;
LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutObject,
DisplayItem::kPrintedContentPDFURLRect,
rect);
if (url.hasFragmentIdentifier() &&
equalIgnoringFragmentIdentifier(url,
m_layoutObject.document().baseURL())) {
String fragmentName = url.fragmentIdentifier();
if (m_layoutObject.document().findAnchor(fragmentName))
paintInfo.context.setURLFragmentForRect(fragmentName, rect);
return;
}
paintInfo.context.setURLForRect(url, rect);
}
void ObjectPainter::drawLineForBoxSide(GraphicsContext& graphicsContext,
int x1,
int y1,
int x2,
int y2,
BoxSide side,
Color color,
EBorderStyle style,
int adjacentWidth1,
int adjacentWidth2,
bool antialias) {
int thickness;
int length;
if (side == BSTop || side == BSBottom) {
thickness = y2 - y1;
length = x2 - x1;
} else {
thickness = x2 - x1;
length = y2 - y1;
}
// We would like this check to be an ASSERT as we don't want to draw empty
// borders. However nothing guarantees that the following recursive calls to
// drawLineForBoxSide will have positive thickness and length.
if (length <= 0 || thickness <= 0)
return;
if (style == BorderStyleDouble && thickness < 3)
style = BorderStyleSolid;
switch (style) {
case BorderStyleNone:
case BorderStyleHidden:
return;
case BorderStyleDotted:
case BorderStyleDashed:
drawDashedOrDottedBoxSide(graphicsContext, x1, y1, x2, y2, side, color,
thickness, style, antialias);
break;
case BorderStyleDouble:
drawDoubleBoxSide(graphicsContext, x1, y1, x2, y2, length, side, color,
thickness, adjacentWidth1, adjacentWidth2, antialias);
break;
case BorderStyleRidge:
case BorderStyleGroove:
drawRidgeOrGrooveBoxSide(graphicsContext, x1, y1, x2, y2, side, color,
style, adjacentWidth1, adjacentWidth2,
antialias);
break;
case BorderStyleInset:
// FIXME: Maybe we should lighten the colors on one side like Firefox.
// https://bugs.webkit.org/show_bug.cgi?id=58608
if (side == BSTop || side == BSLeft)
color = color.dark();
// fall through
case BorderStyleOutset:
if (style == BorderStyleOutset && (side == BSBottom || side == BSRight))
color = color.dark();
// fall through
case BorderStyleSolid:
drawSolidBoxSide(graphicsContext, x1, y1, x2, y2, side, color,
adjacentWidth1, adjacentWidth2, antialias);
break;
}
}
void ObjectPainter::drawDashedOrDottedBoxSide(GraphicsContext& graphicsContext,
int x1,
int y1,
int x2,
int y2,
BoxSide side,
Color color,
int thickness,
EBorderStyle style,
bool antialias) {
ASSERT(thickness > 0);
bool wasAntialiased = graphicsContext.shouldAntialias();
StrokeStyle oldStrokeStyle = graphicsContext.getStrokeStyle();
graphicsContext.setShouldAntialias(antialias);
graphicsContext.setStrokeColor(color);
graphicsContext.setStrokeThickness(thickness);
graphicsContext.setStrokeStyle(style == BorderStyleDashed ? DashedStroke
: DottedStroke);
switch (side) {
case BSBottom:
case BSTop: {
int midY = y1 + thickness / 2;
graphicsContext.drawLine(IntPoint(x1, midY), IntPoint(x2, midY));
break;
}
case BSRight:
case BSLeft: {
int midX = x1 + thickness / 2;
graphicsContext.drawLine(IntPoint(midX, y1), IntPoint(midX, y2));
break;
}
}
graphicsContext.setShouldAntialias(wasAntialiased);
graphicsContext.setStrokeStyle(oldStrokeStyle);
}
void ObjectPainter::drawDoubleBoxSide(GraphicsContext& graphicsContext,
int x1,
int y1,
int x2,
int y2,
int length,
BoxSide side,
Color color,
int thickness,
int adjacentWidth1,
int adjacentWidth2,
bool antialias) {
int thirdOfThickness = (thickness + 1) / 3;
ASSERT(thirdOfThickness > 0);
if (!adjacentWidth1 && !adjacentWidth2) {
StrokeStyle oldStrokeStyle = graphicsContext.getStrokeStyle();
graphicsContext.setStrokeStyle(NoStroke);
graphicsContext.setFillColor(color);
bool wasAntialiased = graphicsContext.shouldAntialias();
graphicsContext.setShouldAntialias(antialias);
switch (side) {
case BSTop:
case BSBottom:
graphicsContext.drawRect(IntRect(x1, y1, length, thirdOfThickness));
graphicsContext.drawRect(
IntRect(x1, y2 - thirdOfThickness, length, thirdOfThickness));
break;
case BSLeft:
case BSRight:
graphicsContext.drawRect(IntRect(x1, y1, thirdOfThickness, length));
graphicsContext.drawRect(
IntRect(x2 - thirdOfThickness, y1, thirdOfThickness, length));
break;
}
graphicsContext.setShouldAntialias(wasAntialiased);
graphicsContext.setStrokeStyle(oldStrokeStyle);
return;
}
int adjacent1BigThird =
((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 3;
int adjacent2BigThird =
((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 3;
switch (side) {
case BSTop:
drawLineForBoxSide(graphicsContext,
x1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0), y1,
x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0),
y1 + thirdOfThickness, side, color, BorderStyleSolid,
adjacent1BigThird, adjacent2BigThird, antialias);
drawLineForBoxSide(
graphicsContext, x1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
y2 - thirdOfThickness, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
y2, side, color, BorderStyleSolid, adjacent1BigThird,
adjacent2BigThird, antialias);
break;
case BSLeft:
drawLineForBoxSide(
graphicsContext, x1, y1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
x1 + thirdOfThickness,
y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), side, color,
BorderStyleSolid, adjacent1BigThird, adjacent2BigThird, antialias);
drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness,
y1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0), x2,
y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), side,
color, BorderStyleSolid, adjacent1BigThird,
adjacent2BigThird, antialias);
break;
case BSBottom:
drawLineForBoxSide(graphicsContext,
x1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0), y1,
x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
y1 + thirdOfThickness, side, color, BorderStyleSolid,
adjacent1BigThird, adjacent2BigThird, antialias);
drawLineForBoxSide(
graphicsContext, x1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
y2 - thirdOfThickness,
x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), y2, side, color,
BorderStyleSolid, adjacent1BigThird, adjacent2BigThird, antialias);
break;
case BSRight:
drawLineForBoxSide(
graphicsContext, x1, y1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
x1 + thirdOfThickness, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
side, color, BorderStyleSolid, adjacent1BigThird, adjacent2BigThird,
antialias);
drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness,
y1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0), x2,
y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), side,
color, BorderStyleSolid, adjacent1BigThird,
adjacent2BigThird, antialias);
break;
default:
break;
}
}
void ObjectPainter::drawRidgeOrGrooveBoxSide(GraphicsContext& graphicsContext,
int x1,
int y1,
int x2,
int y2,
BoxSide side,
Color color,
EBorderStyle style,
int adjacentWidth1,
int adjacentWidth2,
bool antialias) {
EBorderStyle s1;
EBorderStyle s2;
if (style == BorderStyleGroove) {
s1 = BorderStyleInset;
s2 = BorderStyleOutset;
} else {
s1 = BorderStyleOutset;
s2 = BorderStyleInset;
}
int adjacent1BigHalf =
((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 2;
int adjacent2BigHalf =
((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 2;
switch (side) {
case BSTop:
drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1, 0) / 2,
y1, x2 - std::max(-adjacentWidth2, 0) / 2,
(y1 + y2 + 1) / 2, side, color, s1, adjacent1BigHalf,
adjacent2BigHalf, antialias);
drawLineForBoxSide(
graphicsContext, x1 + std::max(adjacentWidth1 + 1, 0) / 2,
(y1 + y2 + 1) / 2, x2 - std::max(adjacentWidth2 + 1, 0) / 2, y2, side,
color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
break;
case BSLeft:
drawLineForBoxSide(
graphicsContext, x1, y1 + std::max(-adjacentWidth1, 0) / 2,
(x1 + x2 + 1) / 2, y2 - std::max(-adjacentWidth2, 0) / 2, side, color,
s1, adjacent1BigHalf, adjacent2BigHalf, antialias);
drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2,
y1 + std::max(adjacentWidth1 + 1, 0) / 2, x2,
y2 - std::max(adjacentWidth2 + 1, 0) / 2, side, color,
s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
break;
case BSBottom:
drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1, 0) / 2,
y1, x2 - std::max(adjacentWidth2, 0) / 2,
(y1 + y2 + 1) / 2, side, color, s2, adjacent1BigHalf,
adjacent2BigHalf, antialias);
drawLineForBoxSide(
graphicsContext, x1 + std::max(-adjacentWidth1 + 1, 0) / 2,
(y1 + y2 + 1) / 2, x2 - std::max(-adjacentWidth2 + 1, 0) / 2, y2,
side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
break;
case BSRight:
drawLineForBoxSide(
graphicsContext, x1, y1 + std::max(adjacentWidth1, 0) / 2,
(x1 + x2 + 1) / 2, y2 - std::max(adjacentWidth2, 0) / 2, side, color,
s2, adjacent1BigHalf, adjacent2BigHalf, antialias);
drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2,
y1 + std::max(-adjacentWidth1 + 1, 0) / 2, x2,
y2 - std::max(-adjacentWidth2 + 1, 0) / 2, side, color,
s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
break;
}
}
void ObjectPainter::drawSolidBoxSide(GraphicsContext& graphicsContext,
int x1,
int y1,
int x2,
int y2,
BoxSide side,
Color color,
int adjacentWidth1,
int adjacentWidth2,
bool antialias) {
ASSERT(x2 >= x1);
ASSERT(y2 >= y1);
if (!adjacentWidth1 && !adjacentWidth2) {
// Tweak antialiasing to match the behavior of fillQuad();
// this matters for rects in transformed contexts.
bool wasAntialiased = graphicsContext.shouldAntialias();
if (antialias != wasAntialiased)
graphicsContext.setShouldAntialias(antialias);
graphicsContext.fillRect(IntRect(x1, y1, x2 - x1, y2 - y1), color);
if (antialias != wasAntialiased)
graphicsContext.setShouldAntialias(wasAntialiased);
return;
}
FloatPoint quad[4];
switch (side) {
case BSTop:
quad[0] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y1);
quad[1] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y2);
quad[2] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y2);
quad[3] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y1);
break;
case BSBottom:
quad[0] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y1);
quad[1] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y2);
quad[2] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y2);
quad[3] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y1);
break;
case BSLeft:
quad[0] = FloatPoint(x1, y1 + std::max(-adjacentWidth1, 0));
quad[1] = FloatPoint(x1, y2 - std::max(-adjacentWidth2, 0));
quad[2] = FloatPoint(x2, y2 - std::max(adjacentWidth2, 0));
quad[3] = FloatPoint(x2, y1 + std::max(adjacentWidth1, 0));
break;
case BSRight:
quad[0] = FloatPoint(x1, y1 + std::max(adjacentWidth1, 0));
quad[1] = FloatPoint(x1, y2 - std::max(adjacentWidth2, 0));
quad[2] = FloatPoint(x2, y2 - std::max(-adjacentWidth2, 0));
quad[3] = FloatPoint(x2, y1 + std::max(-adjacentWidth1, 0));
break;
}
fillQuad(graphicsContext, quad, color, antialias);
}
void ObjectPainter::paintAllPhasesAtomically(const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
// Pass PaintPhaseSelection and PaintPhaseTextClip to the descendants so that
// they will paint for selection and text clip respectively. We don't need
// complete painting for these phases.
if (paintInfo.phase == PaintPhaseSelection ||
paintInfo.phase == PaintPhaseTextClip) {
m_layoutObject.paint(paintInfo, paintOffset);
return;
}
if (paintInfo.phase != PaintPhaseForeground)
return;
PaintInfo info(paintInfo);
info.phase = PaintPhaseBlockBackground;
m_layoutObject.paint(info, paintOffset);
info.phase = PaintPhaseFloat;
m_layoutObject.paint(info, paintOffset);
info.phase = PaintPhaseForeground;
m_layoutObject.paint(info, paintOffset);
info.phase = PaintPhaseOutline;
m_layoutObject.paint(info, paintOffset);
}
} // namespace blink