Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1380)

Unified Diff: Source/core/paint/BoxBorderPainter.cpp

Issue 1159113010: Optimized box border side painting order (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: forgot the new test Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/paint/BoxBorderPainter.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/paint/BoxBorderPainter.cpp
diff --git a/Source/core/paint/BoxBorderPainter.cpp b/Source/core/paint/BoxBorderPainter.cpp
index db6254da46a7b9a4cc51a5eaac9c405f5d8035c5..fca26cfb83c3d15dab589260c17c0fa1c5e0d1a5 100644
--- a/Source/core/paint/BoxBorderPainter.cpp
+++ b/Source/core/paint/BoxBorderPainter.cpp
@@ -10,6 +10,8 @@
#include "core/style/BorderEdge.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/GraphicsContextStateSaver.h"
+#include "wtf/Vector.h"
+#include <algorithm>
namespace blink {
@@ -106,29 +108,14 @@ inline bool borderWillArcInnerEdge(const FloatSize& firstRadius, const FloatSize
return !firstRadius.isZero() || !secondRadius.isZero();
}
-// This assumes that we draw in order: top, bottom, left, right.
-inline bool willBeOverdrawn(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
+inline bool willOverdraw(BoxSide side, EBorderStyle style, BorderEdgeFlags completedEdges)
{
- switch (side) {
- case BSTop:
- case BSBottom:
- if (edges[adjacentSide].presentButInvisible())
- return false;
-
- if (!edges[side].sharesColorWith(edges[adjacentSide]) && edges[adjacentSide].color.hasAlpha())
- return false;
-
- if (!borderStyleFillsBorderArea(edges[adjacentSide].borderStyle()))
- return false;
-
- return true;
-
- case BSLeft:
- case BSRight:
- // These draw last, so are never overdrawn.
+ // If we're done with this side, it will obviously not overdraw any portion of the current edge.
+ if (includesEdge(completedEdges, side))
return false;
- }
- return false;
+
+ // The side is still to be drawn. It overdraws the current edge iff it has a solid fill style.
+ return borderStyleFillsBorderArea(style);
}
inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorderStyle style, EBorderStyle adjacentStyle)
@@ -145,12 +132,13 @@ inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorder
return borderStyleHasUnmatchedColorsAtCorner(style, side, adjacentSide);
}
-inline bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[], bool allowOverdraw)
+inline bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[],
+ bool allowOverdraw, BorderEdgeFlags completedEdges)
{
- if ((edges[side].isTransparent && edges[adjacentSide].isTransparent) || !edges[adjacentSide].isPresent)
+ if (!edges[adjacentSide].isPresent)
return false;
- if (allowOverdraw && willBeOverdrawn(side, adjacentSide, edges))
+ if (allowOverdraw && willOverdraw(adjacentSide, edges[adjacentSide].borderStyle(), completedEdges))
return false;
if (!edges[side].sharesColorWith(edges[adjacentSide]))
@@ -360,8 +348,134 @@ bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance)
return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == BackgroundBleedClipLayer;
}
+// The LUTs below assume specific enum values.
+static_assert(BNONE == 0, "unexpected EBorderStyle value");
+static_assert(BHIDDEN == 1, "unexpected EBorderStyle value");
+static_assert(INSET == 2, "unexpected EBorderStyle value");
+static_assert(GROOVE == 3, "unexpected EBorderStyle value");
+static_assert(OUTSET == 4, "unexpected EBorderStyle value");
+static_assert(RIDGE == 5, "unexpected EBorderStyle value");
+static_assert(DOTTED == 6, "unexpected EBorderStyle value");
+static_assert(DASHED == 7, "unexpected EBorderStyle value");
+static_assert(SOLID == 8, "unexpected EBorderStyle value");
+static_assert(DOUBLE == 9, "unexpected EBorderStyle value");
+
+static_assert(BSTop == 0, "unexpected BoxSide value");
+static_assert(BSRight == 1, "unexpected BoxSide value");
+static_assert(BSBottom == 2, "unexpected BoxSide value");
+static_assert(BSLeft == 3, "unexpected BoxSide value");
+
+// Style-based paint order: non-solid edges (dashed/dotted/double) are painted before
+// solid edges (inset/outset/groove/ridge/solid) to maximize overdraw opportunities.
+const unsigned kStylePriority[] = {
+ 0 /* BNONE */,
+ 0 /* BHIDDEN */,
+ 2 /* INSET */,
+ 2 /* GROOVE */,
+ 2 /* OUTSET */,
+ 2 /* RIDGE */,
+ 1 /* DOTTED */,
+ 1 /* DASHED */,
+ 3 /* SOLID */,
+ 1 /* DOUBLE */
+};
+
+// Given the same style, prefer drawing in non-adjacent order to minimize the number of sides
+// which require mitres.
+const unsigned kSidePriority[] = {
+ 0, /* BSTop */
+ 2, /* BSRight */
+ 1, /* BSBottom */
+ 3, /* BSLeft */
+};
+
+// Edges sharing the same opacity. Stores both a side list and an edge bitfield to support
+// constant time iteration + membership tests.
+struct OpacityGroup {
+ OpacityGroup(unsigned alpha) : edgeFlags(0), alpha(alpha) { }
+
+ Vector<BoxSide, 4> sides;
+ BorderEdgeFlags edgeFlags;
+ unsigned alpha;
+};
+
} // anonymous namespace
+// Holds edges grouped by opacity and sorted in paint order.
+struct BoxBorderPainter::ComplexBorderInfo {
+ ComplexBorderInfo(const BoxBorderPainter& borderPainter, bool antiAlias)
+ : antiAlias(antiAlias)
+ {
+ Vector<BoxSide, 4> sortedSides;
+
+ // First, collect all visible sides.
+ for (unsigned i = borderPainter.m_firstVisibleEdge; i < 4; ++i) {
+ BoxSide side = static_cast<BoxSide>(i);
+
+ if (includesEdge(borderPainter.m_visibleEdgeSet, side))
+ sortedSides.append(side);
+ }
+ ASSERT(!sortedSides.isEmpty());
+
+ // Then sort them in paint order, based on three (prioritized) criteria: alpha, style, side.
+ std::sort(sortedSides.begin(), sortedSides.end(),
+ [&borderPainter] (BoxSide a, BoxSide b) -> bool {
+ const BorderEdge& edgeA = borderPainter.m_edges[a];
+ const BorderEdge& edgeB = borderPainter.m_edges[b];
+
+ const unsigned alphaA = edgeA.color.alpha();
+ const unsigned alphaB = edgeB.color.alpha();
+ if (alphaA != alphaB)
+ return alphaA < alphaB;
+
+ const unsigned stylePriorityA = kStylePriority[edgeA.borderStyle()];
+ const unsigned stylePriorityB = kStylePriority[edgeB.borderStyle()];
+ if (stylePriorityA != stylePriorityB)
+ return stylePriorityA < stylePriorityB;
+
+ return kSidePriority[a] < kSidePriority[b];
+ });
+
+ // Finally, build the opacity group structures.
+ buildOpacityGroups(borderPainter, sortedSides);
+
+ if (borderPainter.m_isRounded)
+ roundedBorderPath.addRoundedRect(borderPainter.m_outer);
+ }
+
+ Vector<OpacityGroup, 4> opacityGroups;
+
+ // Potentially used when drawing rounded borders.
+ Path roundedBorderPath;
+
+ bool antiAlias;
+
+private:
+ void buildOpacityGroups(const BoxBorderPainter& borderPainter,
+ const Vector<BoxSide, 4>& sortedSides)
+ {
+ unsigned currentAlpha = 0;
+ for (BoxSide side : sortedSides) {
+ const BorderEdge& edge = borderPainter.m_edges[side];
+ const unsigned edgeAlpha = edge.color.alpha();
+
+ ASSERT(edgeAlpha > 0);
+ ASSERT(edgeAlpha >= currentAlpha);
+ if (edgeAlpha != currentAlpha) {
+ opacityGroups.append(OpacityGroup(edgeAlpha));
+ currentAlpha = edgeAlpha;
+ }
+
+ ASSERT(!opacityGroups.isEmpty());
+ OpacityGroup& currentGroup = opacityGroups.last();
+ currentGroup.sides.append(side);
+ currentGroup.edgeFlags |= edgeFlagForSide(side);
+ }
+
+ ASSERT(!opacityGroups.isEmpty());
+ }
+};
+
void BoxBorderPainter::drawDoubleBorder(GraphicsContext* context, const LayoutRect& borderRect) const
{
ASSERT(m_isUniformColor);
@@ -447,6 +561,7 @@ BoxBorderPainter::BoxBorderPainter(const LayoutRect& borderRect, const ComputedS
, m_isUniformStyle(true)
, m_isUniformWidth(true)
, m_isUniformColor(true)
+ , m_isRounded(false)
, m_hasAlpha(false)
{
style.getBorderEdgeInfo(m_edges, includeLogicalLeftEdge, includeLogicalRightEdge);
@@ -493,6 +608,8 @@ BoxBorderPainter::BoxBorderPainter(const LayoutRect& borderRect, const ComputedS
&& m_outer.isRounded()
&& BoxPainter::allCornersClippedOut(m_outer, clipRect))
m_outer.setRadii(FloatRoundedRect::Radii());
+
+ m_isRounded = m_outer.isRounded();
}
void BoxBorderPainter::paintBorder(const PaintInfo& info, const LayoutRect& rect) const
@@ -520,69 +637,181 @@ void BoxBorderPainter::paintBorder(const PaintInfo& info, const LayoutRect& rect
// If only one edge visible antialiasing doesn't create seams
bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext) || m_visibleEdgeCount == 1;
- if (m_hasAlpha) {
- paintTranslucentBorderSides(graphicsContext, antialias);
- } else {
- paintBorderSides(graphicsContext, m_visibleEdgeSet, antialias);
+
+ const ComplexBorderInfo borderInfo(*this, antialias);
+ paintOpacityGroup(graphicsContext, borderInfo, 0, 1);
+}
+
+// In order to maximize the use of overdraw as a corner seam avoidance technique, we draw
+// translucent border sides using the following algorithm:
+//
+// 1) cluster sides sharing the same opacity into "opacity groups" [ComplexBorderInfo]
+// 2) sort groups in increasing opacity order [ComplexBorderInfo]
+// 3) reverse-iterate over groups (decreasing opacity order), pushing nested transparency
+// layers with adjusted/relative opacity [paintOpacityGroup]
+// 4) iterate over groups (increasing opacity order), painting actual group contents and
+// then ending their corresponding transparency layer [paintOpacityGroup]
+//
+// Layers are created in decreasing opacity order (top -> bottom), while actual border sides are
+// drawn in increasing opacity order (bottom -> top). At each level, opacity is adjusted to acount
+// for accumulated/ancestor layer alpha. Because opacity is applied via layers, the actual draw
+// paint is opaque.
+//
+// As an example, let's consider a border with the following sides/opacities:
+//
+// top: 1.0
+// right: 0.25
+// bottom: 0.5
+// left: 0.25
+//
+// These are grouped and sorted in ComplexBorderInfo as follows:
+//
+// group[0]: { alpha: 1.0, sides: top }
+// group[1]: { alpha: 0.5, sides: bottom }
+// group[2]: { alpha: 0.25, sides: right, left }
+//
+// Applying the algorithm yields the following paint sequence:
+//
+// // no layer needed for group 0 (alpha == 1)
+// beginLayer(0.5) // layer for group 1
+// beginLayer(0.5) // layer for group 2 (effective opacity: 0.5 * 0.5 == 0.25)
+// paintSides(right, left) // paint group 2
+// endLayer
+// paintSides(bottom) // paint group 1
+// endLayer
+// paintSides(top) // paint group 0
+//
+// Note that we're always drawing using opaque paints on top of less-opaque content - hence
+// we can use overdraw to mask portions of the previous sides.
+//
+BorderEdgeFlags BoxBorderPainter::paintOpacityGroup(GraphicsContext* context,
+ const ComplexBorderInfo& borderInfo, unsigned index, float effectiveOpacity) const
+{
+ ASSERT(effectiveOpacity > 0 && effectiveOpacity <= 1);
+
+ const size_t opacityGroupCount = borderInfo.opacityGroups.size();
+
+ // For overdraw logic purposes, treat missing/transparent edges as completed.
+ if (index >= opacityGroupCount)
+ return ~m_visibleEdgeSet;
+
+ // Groups are sorted in increasing opacity order, but we need to create layers in
+ // decreasing opacity order - hence the reverse iteration.
+ const OpacityGroup& group = borderInfo.opacityGroups[opacityGroupCount - index - 1];
+
+ // Adjust this group's paint opacity to account for ancestor transparency layers
+ // (needed in case we avoid creating a layer below).
+ unsigned paintAlpha = group.alpha / effectiveOpacity;
+ ASSERT(paintAlpha <= 255);
+
+ // For the last (bottom) group, we can skip the layer even in the presence of opacity iff
+ // it contains no adjecent edges (no in-group overdraw possibility).
+ bool needsLayer = group.alpha != 255
+ && (includesAdjacentEdges(group.edgeFlags) || (index + 1 < borderInfo.opacityGroups.size()));
+
+ if (needsLayer) {
+ const float groupOpacity = static_cast<float>(group.alpha) / 255;
+ ASSERT(groupOpacity < effectiveOpacity);
+
+ context->beginLayer(groupOpacity / effectiveOpacity);
+ effectiveOpacity = groupOpacity;
+
+ // Group opacity is applied via a layer => we draw the members using opaque paint.
+ paintAlpha = 255;
+ }
+
+ // Recursion may seem unpalatable here, but
+ // a) it has an upper bound of 4
+ // b) only triggers at all when mixing border sides with different opacities
+ // c) it allows us to express the layer nesting algorithm more naturally
+ BorderEdgeFlags completedEdges = paintOpacityGroup(context, borderInfo, index + 1, effectiveOpacity);
+
+ // Paint the actual group edges with an alpha adjusted to account for ancenstor layers opacity.
+ for (BoxSide side : group.sides) {
+ paintSide(context, borderInfo, side, paintAlpha, completedEdges);
+ completedEdges |= edgeFlagForSide(side);
}
+
+ if (needsLayer)
+ context->endLayer();
+
+ return completedEdges;
}
-void BoxBorderPainter::paintTranslucentBorderSides(GraphicsContext* graphicsContext,
- bool antialias) const
+void BoxBorderPainter::paintSide(GraphicsContext* context, const ComplexBorderInfo& borderInfo,
+ BoxSide side, unsigned alpha, BorderEdgeFlags completedEdges) const
{
- // willBeOverdrawn assumes that we draw in order: top, bottom, left, right.
- // This is different from BoxSide enum order.
- static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight };
-
- BorderEdgeFlags edgesToDraw = m_visibleEdgeSet;
- while (edgesToDraw) {
- // Find undrawn edges sharing a color.
- Color commonColor;
-
- BorderEdgeFlags commonColorEdgeSet = 0;
- for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i) {
- BoxSide currSide = paintOrder[i];
- if (!includesEdge(edgesToDraw, currSide))
- continue;
-
- bool includeEdge;
- if (!commonColorEdgeSet) {
- commonColor = m_edges[currSide].color;
- includeEdge = true;
- } else {
- includeEdge = m_edges[currSide].color == commonColor;
- }
+ const BorderEdge& edge = m_edges[side];
+ ASSERT(edge.shouldRender());
+ const Color color(edge.color.red(), edge.color.green(), edge.color.blue(), alpha);
- if (includeEdge)
- commonColorEdgeSet |= edgeFlagForSide(currSide);
- }
+ FloatRect sideRect = m_outer.rect();
+ const Path* path = nullptr;
- bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) && commonColor.hasAlpha();
- if (useTransparencyLayer) {
- graphicsContext->beginLayer(static_cast<float>(commonColor.alpha()) / 255);
- commonColor = Color(commonColor.red(), commonColor.green(), commonColor.blue());
- }
+ // TODO(fmalita): find a way to consolidate these without sacrificing readability.
+ switch (side) {
+ case BSTop: {
+ bool usePath = m_isRounded && (borderStyleHasInnerDetail(edge.borderStyle())
+ || borderWillArcInnerEdge(m_inner.radii().topLeft(), m_inner.radii().topRight()));
+ if (usePath)
+ path = &borderInfo.roundedBorderPath;
+ else
+ sideRect.setHeight(edge.width);
+
+ paintOneBorderSide(context, sideRect, BSTop, BSLeft, BSRight, path, borderInfo.antiAlias,
+ color, completedEdges);
+ break;
+ }
+ case BSBottom: {
+ bool usePath = m_isRounded && (borderStyleHasInnerDetail(edge.borderStyle())
+ || borderWillArcInnerEdge(m_inner.radii().bottomLeft(), m_inner.radii().bottomRight()));
+ if (usePath)
+ path = &borderInfo.roundedBorderPath;
+ else
+ sideRect.shiftYEdgeTo(sideRect.maxY() - edge.width);
- paintBorderSides(graphicsContext, commonColorEdgeSet, antialias, &commonColor);
+ paintOneBorderSide(context, sideRect, BSBottom, BSLeft, BSRight, path, borderInfo.antiAlias,
+ color, completedEdges);
+ break;
+ }
+ case BSLeft: {
+ bool usePath = m_isRounded && (borderStyleHasInnerDetail(edge.borderStyle())
+ || borderWillArcInnerEdge(m_inner.radii().bottomLeft(), m_inner.radii().topLeft()));
+ if (usePath)
+ path = &borderInfo.roundedBorderPath;
+ else
+ sideRect.setWidth(edge.width);
- if (useTransparencyLayer)
- graphicsContext->endLayer();
+ paintOneBorderSide(context, sideRect, BSLeft, BSTop, BSBottom, path, borderInfo.antiAlias,
+ color, completedEdges);
+ break;
+ }
+ case BSRight: {
+ bool usePath = m_isRounded && (borderStyleHasInnerDetail(edge.borderStyle())
+ || borderWillArcInnerEdge(m_inner.radii().bottomRight(), m_inner.radii().topRight()));
+ if (usePath)
+ path = &borderInfo.roundedBorderPath;
+ else
+ sideRect.shiftXEdgeTo(sideRect.maxX() - edge.width);
- edgesToDraw &= ~commonColorEdgeSet;
+ paintOneBorderSide(context, sideRect, BSRight, BSTop, BSBottom, path, borderInfo.antiAlias,
+ color, completedEdges);
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
}
}
void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext,
const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adjacentSide2,
- const Path* path, bool antialias, const Color* overrideColor) const
+ const Path* path, bool antialias, Color color, BorderEdgeFlags completedEdges) const
{
const BorderEdge& edgeToRender = m_edges[side];
ASSERT(edgeToRender.width);
const BorderEdge& adjacentEdge1 = m_edges[adjacentSide1];
const BorderEdge& adjacentEdge2 = m_edges[adjacentSide2];
- const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.color;
-
if (path) {
bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, m_edges);
bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, m_edges);
@@ -594,10 +823,10 @@ void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext,
clipBorderSideForComplexInnerPath(graphicsContext, side);
float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.width), adjacentEdge2.width);
drawBoxSideFromPath(graphicsContext, LayoutRect(m_outer.rect()), *path, edgeToRender.width,
- thickness, side, colorToPaint, edgeToRender.borderStyle());
+ thickness, side, color, edgeToRender.borderStyle());
} else {
- bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, m_edges, !antialias);
- bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, m_edges, !antialias);
+ bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, m_edges, !antialias, completedEdges);
+ bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, m_edges, !antialias, completedEdges);
bool clipForStyle = styleRequiresClipPolygon(edgeToRender.borderStyle())
&& (mitreAdjacentSide1 || mitreAdjacentSide2);
@@ -616,78 +845,11 @@ void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext,
}
ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRect.y(),
- sideRect.maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.borderStyle(),
+ sideRect.maxX(), sideRect.maxY(), side, color, edgeToRender.borderStyle(),
mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? adjacentEdge2.width : 0, antialias);
}
}
-void BoxBorderPainter::paintBorderSides(GraphicsContext* graphicsContext, BorderEdgeFlags edgeSet,
- bool antialias, const Color* overrideColor) const
-{
- bool renderRadii = m_outer.isRounded();
-
- Path roundedPath;
- if (renderRadii)
- roundedPath.addRoundedRect(m_outer);
-
- // The inner border adjustment for bleed avoidance mode BackgroundBleedBackgroundOverBorder
- // is only applied to sideRect, which is okay since BackgroundBleedBackgroundOverBorder
- // is only to be used for solid borders and the shape of the border painted by drawBoxSideFromPath
- // only depends on sideRect when painting solid borders.
-
- if (includesEdge(edgeSet, BSTop)) {
- const BorderEdge& edge = m_edges[BSTop];
- ASSERT(edge.shouldRender());
-
- FloatRect sideRect = m_outer.rect();
- sideRect.setHeight(edge.width);
-
- bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyle())
- || borderWillArcInnerEdge(m_inner.radii().topLeft(), m_inner.radii().topRight()));
- paintOneBorderSide(graphicsContext, sideRect, BSTop, BSLeft, BSRight,
- usePath ? &roundedPath : 0, antialias, overrideColor);
- }
-
- if (includesEdge(edgeSet, BSBottom)) {
- const BorderEdge& edge = m_edges[BSBottom];
- ASSERT(edge.shouldRender());
-
- FloatRect sideRect = m_outer.rect();
- sideRect.shiftYEdgeTo(sideRect.maxY() - edge.width);
-
- bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyle())
- || borderWillArcInnerEdge(m_inner.radii().bottomLeft(), m_inner.radii().bottomRight()));
- paintOneBorderSide(graphicsContext, sideRect, BSBottom, BSLeft, BSRight,
- usePath ? &roundedPath : 0, antialias, overrideColor);
- }
-
- if (includesEdge(edgeSet, BSLeft)) {
- const BorderEdge& edge = m_edges[BSLeft];
- ASSERT(edge.shouldRender());
-
- FloatRect sideRect = m_outer.rect();
- sideRect.setWidth(edge.width);
-
- bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyle())
- || borderWillArcInnerEdge(m_inner.radii().bottomLeft(), m_inner.radii().topLeft()));
- paintOneBorderSide(graphicsContext, sideRect, BSLeft, BSTop, BSBottom,
- usePath ? &roundedPath : 0, antialias, overrideColor);
- }
-
- if (includesEdge(edgeSet, BSRight)) {
- const BorderEdge& edge = m_edges[BSRight];
- ASSERT(edge.shouldRender());
-
- FloatRect sideRect = m_outer.rect();
- sideRect.shiftXEdgeTo(sideRect.maxX() - edge.width);
-
- bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyle())
- || borderWillArcInnerEdge(m_inner.radii().bottomRight(), m_inner.radii().topRight()));
- paintOneBorderSide(graphicsContext, sideRect, BSRight, BSTop, BSBottom,
- usePath ? &roundedPath : 0, antialias, overrideColor);
- }
-}
-
void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext,
const LayoutRect& borderRect, const Path& borderPath, float thickness, float drawThickness,
BoxSide side, Color color, EBorderStyle borderStyle) const
« no previous file with comments | « Source/core/paint/BoxBorderPainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698