| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/paint/BoxBorderPainter.h" | 6 #include "core/paint/BoxBorderPainter.h" |
| 7 | 7 |
| 8 #include "core/paint/BoxPainter.h" | 8 #include "core/paint/BoxPainter.h" |
| 9 #include "core/paint/PaintInfo.h" | 9 #include "core/paint/PaintInfo.h" |
| 10 #include "core/style/BorderEdge.h" | 10 #include "core/style/BorderEdge.h" |
| 11 #include "platform/RuntimeEnabledFeatures.h" |
| 11 #include "platform/graphics/GraphicsContext.h" | 12 #include "platform/graphics/GraphicsContext.h" |
| 12 #include "platform/graphics/GraphicsContextStateSaver.h" | 13 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 13 #include "wtf/Vector.h" | 14 #include "wtf/Vector.h" |
| 14 #include <algorithm> | 15 #include <algorithm> |
| 15 | 16 |
| 16 namespace blink { | 17 namespace blink { |
| 17 | 18 |
| 18 namespace { | 19 namespace { |
| 19 | 20 |
| 20 enum BorderEdgeFlag { | 21 enum BorderEdgeFlag { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 inline bool willOverdraw(BoxSide side, EBorderStyle style, BorderEdgeFlags compl
etedEdges) | 98 inline bool willOverdraw(BoxSide side, EBorderStyle style, BorderEdgeFlags compl
etedEdges) |
| 98 { | 99 { |
| 99 // If we're done with this side, it will obviously not overdraw any portion
of the current edge. | 100 // If we're done with this side, it will obviously not overdraw any portion
of the current edge. |
| 100 if (includesEdge(completedEdges, side)) | 101 if (includesEdge(completedEdges, side)) |
| 101 return false; | 102 return false; |
| 102 | 103 |
| 103 // The side is still to be drawn. It overdraws the current edge iff it has a
solid fill style. | 104 // The side is still to be drawn. It overdraws the current edge iff it has a
solid fill style. |
| 104 return borderStyleFillsBorderArea(style); | 105 return borderStyleFillsBorderArea(style); |
| 105 } | 106 } |
| 106 | 107 |
| 107 inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorder
Style style, EBorderStyle adjacentStyle) | 108 inline bool borderStylesRequireMiter(BoxSide side, BoxSide adjacentSide, EBorder
Style style, EBorderStyle adjacentStyle) |
| 108 { | 109 { |
| 109 if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE ||
adjacentStyle == RIDGE) | 110 if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE ||
adjacentStyle == RIDGE) |
| 110 return true; | 111 return true; |
| 111 | 112 |
| 112 if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjace
ntStyle)) | 113 if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjace
ntStyle)) |
| 113 return true; | 114 return true; |
| 114 | 115 |
| 115 if (style != adjacentStyle) | 116 if (style != adjacentStyle) |
| 116 return true; | 117 return true; |
| 117 | 118 |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 2 /* GROOVE */, | 343 2 /* GROOVE */, |
| 343 2 /* OUTSET */, | 344 2 /* OUTSET */, |
| 344 2 /* RIDGE */, | 345 2 /* RIDGE */, |
| 345 1 /* DOTTED */, | 346 1 /* DOTTED */, |
| 346 1 /* DASHED */, | 347 1 /* DASHED */, |
| 347 3 /* SOLID */, | 348 3 /* SOLID */, |
| 348 1 /* DOUBLE */ | 349 1 /* DOUBLE */ |
| 349 }; | 350 }; |
| 350 | 351 |
| 351 // Given the same style, prefer drawing in non-adjacent order to minimize the nu
mber of sides | 352 // Given the same style, prefer drawing in non-adjacent order to minimize the nu
mber of sides |
| 352 // which require mitres. | 353 // which require miters. |
| 353 const unsigned kSidePriority[] = { | 354 const unsigned kSidePriority[] = { |
| 354 0, /* BSTop */ | 355 0, /* BSTop */ |
| 355 2, /* BSRight */ | 356 2, /* BSRight */ |
| 356 1, /* BSBottom */ | 357 1, /* BSBottom */ |
| 357 3, /* BSLeft */ | 358 3, /* BSLeft */ |
| 358 }; | 359 }; |
| 359 | 360 |
| 360 // Edges sharing the same opacity. Stores both a side list and an edge bitfield
to support | 361 // Edges sharing the same opacity. Stores both a side list and an edge bitfield
to support |
| 361 // constant time iteration + membership tests. | 362 // constant time iteration + membership tests. |
| 362 struct OpacityGroup { | 363 struct OpacityGroup { |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already
applied. | 597 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already
applied. |
| 597 if (!bleedAvoidanceIsClipping(m_bleedAvoidance)) | 598 if (!bleedAvoidanceIsClipping(m_bleedAvoidance)) |
| 598 graphicsContext->clipRoundedRect(m_outer); | 599 graphicsContext->clipRoundedRect(m_outer); |
| 599 | 600 |
| 600 // For BackgroundBleedBackgroundOverBorder, we're going to draw an opaqu
e background over | 601 // For BackgroundBleedBackgroundOverBorder, we're going to draw an opaqu
e background over |
| 601 // the inner rrect - so clipping is not needed (nor desirable due to bac
kdrop bleeding). | 602 // the inner rrect - so clipping is not needed (nor desirable due to bac
kdrop bleeding). |
| 602 if (m_bleedAvoidance != BackgroundBleedBackgroundOverBorder && m_inner.i
sRenderable() && !m_inner.isEmpty()) | 603 if (m_bleedAvoidance != BackgroundBleedBackgroundOverBorder && m_inner.i
sRenderable() && !m_inner.isEmpty()) |
| 603 graphicsContext->clipOutRoundedRect(m_inner); | 604 graphicsContext->clipOutRoundedRect(m_inner); |
| 604 } | 605 } |
| 605 | 606 |
| 606 // If only one edge visible antialiasing doesn't create seams | 607 bool antialias = |
| 607 bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext) || m_visi
bleEdgeCount == 1; | 608 RuntimeEnabledFeatures::slimmingPaintEnabled() |
| 609 || m_visibleEdgeCount == 1 |
| 610 || BoxPainter::shouldAntialiasLines(graphicsContext); |
| 608 | 611 |
| 609 const ComplexBorderInfo borderInfo(*this, antialias); | 612 const ComplexBorderInfo borderInfo(*this, antialias); |
| 610 paintOpacityGroup(graphicsContext, borderInfo, 0, 1); | 613 paintOpacityGroup(graphicsContext, borderInfo, 0, 1); |
| 611 } | 614 } |
| 612 | 615 |
| 613 // In order to maximize the use of overdraw as a corner seam avoidance technique
, we draw | 616 // In order to maximize the use of overdraw as a corner seam avoidance technique
, we draw |
| 614 // translucent border sides using the following algorithm: | 617 // translucent border sides using the following algorithm: |
| 615 // | 618 // |
| 616 // 1) cluster sides sharing the same opacity into "opacity groups" [ComplexBor
derInfo] | 619 // 1) cluster sides sharing the same opacity into "opacity groups" [ComplexBor
derInfo] |
| 617 // 2) sort groups in increasing opacity order [ComplexBorderInfo] | 620 // 2) sort groups in increasing opacity order [ComplexBorderInfo] |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 764 | 767 |
| 765 paintOneBorderSide(context, sideRect, BSRight, BSTop, BSBottom, path, bo
rderInfo.antiAlias, | 768 paintOneBorderSide(context, sideRect, BSRight, BSTop, BSBottom, path, bo
rderInfo.antiAlias, |
| 766 color, completedEdges); | 769 color, completedEdges); |
| 767 break; | 770 break; |
| 768 } | 771 } |
| 769 default: | 772 default: |
| 770 ASSERT_NOT_REACHED(); | 773 ASSERT_NOT_REACHED(); |
| 771 } | 774 } |
| 772 } | 775 } |
| 773 | 776 |
| 774 BoxBorderPainter::MitreType BoxBorderPainter::computeMitre(BoxSide side, BoxSide
adjacentSide, | 777 BoxBorderPainter::MiterType BoxBorderPainter::computeMiter(BoxSide side, BoxSide
adjacentSide, |
| 775 BorderEdgeFlags completedEdges, bool antialias) const | 778 BorderEdgeFlags completedEdges, bool antialias) const |
| 776 { | 779 { |
| 777 const BorderEdge& adjacentEdge = m_edges[adjacentSide]; | 780 const BorderEdge& adjacentEdge = m_edges[adjacentSide]; |
| 778 | 781 |
| 779 // No miters for missing edges. | 782 // No miters for missing edges. |
| 780 if (!adjacentEdge.isPresent) | 783 if (!adjacentEdge.isPresent) |
| 781 return NoMitre; | 784 return NoMiter; |
| 782 | 785 |
| 783 // Legacy behavior - preserve for now. | 786 // The adjacent edge will overdraw this corner, resulting in a correct miter
. |
| 784 bool allowOverdraw = !antialias; | 787 if (willOverdraw(adjacentSide, adjacentEdge.borderStyle(), completedEdges)) |
| 788 return NoMiter; |
| 785 | 789 |
| 786 // The adjacent edge will overdraw this corner, resulting in a correct mitre
. | 790 // Color transitions require miters. Use miters compatible with the AA drawi
ng mode to avoid |
| 787 if (allowOverdraw && willOverdraw(adjacentSide, adjacentEdge.borderStyle(),
completedEdges)) | |
| 788 return NoMitre; | |
| 789 | |
| 790 // Color transitions require mitres. Use mitres compatible with the AA drawi
ng mode to avoid | |
| 791 // introducing extra clips. | 791 // introducing extra clips. |
| 792 if (!colorsMatchAtCorner(side, adjacentSide, m_edges)) | 792 if (!colorsMatchAtCorner(side, adjacentSide, m_edges)) |
| 793 return antialias ? SoftMitre : HardMitre; | 793 return antialias ? SoftMiter : HardMiter; |
| 794 | 794 |
| 795 // Non-anti-aliased mitres ensure correct same-color seaming when required b
y style. | 795 // Non-anti-aliased miters ensure correct same-color seaming when required b
y style. |
| 796 if (borderStylesRequireMitre(side, adjacentSide, m_edges[side].borderStyle()
, adjacentEdge.borderStyle())) | 796 if (borderStylesRequireMiter(side, adjacentSide, m_edges[side].borderStyle()
, adjacentEdge.borderStyle())) |
| 797 return HardMitre; | 797 return HardMiter; |
| 798 | 798 |
| 799 // Overdraw the adjacent edge when the colors match and we have no style res
trictions. | 799 // Overdraw the adjacent edge when the colors match and we have no style res
trictions. |
| 800 return NoMitre; | 800 return NoMiter; |
| 801 } | 801 } |
| 802 | 802 |
| 803 bool BoxBorderPainter::mitresRequireClipping(MitreType mitre1, MitreType mitre2,
EBorderStyle style, | 803 bool BoxBorderPainter::mitersRequireClipping(MiterType miter1, MiterType miter2,
EBorderStyle style, |
| 804 bool antialias) | 804 bool antialias) |
| 805 { | 805 { |
| 806 // Clipping is required if any of the present mitres doesn't match the curre
nt AA mode. | 806 // Clipping is required if any of the present miters doesn't match the curre
nt AA mode. |
| 807 bool shouldClip = antialias | 807 bool shouldClip = antialias |
| 808 ? mitre1 == HardMitre || mitre2 == HardMitre | 808 ? miter1 == HardMiter || miter2 == HardMiter |
| 809 : mitre1 == SoftMitre || mitre2 == SoftMitre; | 809 : miter1 == SoftMiter || miter2 == SoftMiter; |
| 810 | 810 |
| 811 // Some styles require clipping for any type of mitre. | 811 // Some styles require clipping for any type of miter. |
| 812 shouldClip = shouldClip | 812 shouldClip = shouldClip |
| 813 || ((mitre1 != NoMitre || mitre2 != NoMitre) && styleRequiresClipPolygon
(style)); | 813 || ((miter1 != NoMiter || miter2 != NoMiter) && styleRequiresClipPolygon
(style)); |
| 814 | 814 |
| 815 return shouldClip; | 815 return shouldClip; |
| 816 } | 816 } |
| 817 | 817 |
| 818 void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext, | 818 void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext, |
| 819 const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adja
centSide2, | 819 const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adja
centSide2, |
| 820 const Path* path, bool antialias, Color color, BorderEdgeFlags completedEdge
s) const | 820 const Path* path, bool antialias, Color color, BorderEdgeFlags completedEdge
s) const |
| 821 { | 821 { |
| 822 const BorderEdge& edgeToRender = m_edges[side]; | 822 const BorderEdge& edgeToRender = m_edges[side]; |
| 823 ASSERT(edgeToRender.width); | 823 ASSERT(edgeToRender.width); |
| 824 const BorderEdge& adjacentEdge1 = m_edges[adjacentSide1]; | 824 const BorderEdge& adjacentEdge1 = m_edges[adjacentSide1]; |
| 825 const BorderEdge& adjacentEdge2 = m_edges[adjacentSide2]; | 825 const BorderEdge& adjacentEdge2 = m_edges[adjacentSide2]; |
| 826 | 826 |
| 827 if (path) { | 827 if (path) { |
| 828 MitreType mitre1 = colorsMatchAtCorner(side, adjacentSide1, m_edges) ? H
ardMitre : SoftMitre; | 828 MiterType miter1 = colorsMatchAtCorner(side, adjacentSide1, m_edges) ? H
ardMiter : SoftMiter; |
| 829 MitreType mitre2 = colorsMatchAtCorner(side, adjacentSide2, m_edges) ? H
ardMitre : SoftMitre; | 829 MiterType miter2 = colorsMatchAtCorner(side, adjacentSide2, m_edges) ? H
ardMiter : SoftMiter; |
| 830 | 830 |
| 831 GraphicsContextStateSaver stateSaver(*graphicsContext); | 831 GraphicsContextStateSaver stateSaver(*graphicsContext); |
| 832 if (m_inner.isRenderable()) | 832 if (m_inner.isRenderable()) |
| 833 clipBorderSidePolygon(graphicsContext, side, mitre1, mitre2); | 833 clipBorderSidePolygon(graphicsContext, side, miter1, miter2); |
| 834 else | 834 else |
| 835 clipBorderSideForComplexInnerPath(graphicsContext, side); | 835 clipBorderSideForComplexInnerPath(graphicsContext, side); |
| 836 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi
dth), adjacentEdge2.width); | 836 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi
dth), adjacentEdge2.width); |
| 837 drawBoxSideFromPath(graphicsContext, LayoutRect(m_outer.rect()), *path,
edgeToRender.width, | 837 drawBoxSideFromPath(graphicsContext, LayoutRect(m_outer.rect()), *path,
edgeToRender.width, |
| 838 thickness, side, color, edgeToRender.borderStyle()); | 838 thickness, side, color, edgeToRender.borderStyle()); |
| 839 } else { | 839 } else { |
| 840 MitreType mitre1 = computeMitre(side, adjacentSide1, completedEdges, ant
ialias); | 840 MiterType miter1 = computeMiter(side, adjacentSide1, completedEdges, ant
ialias); |
| 841 MitreType mitre2 = computeMitre(side, adjacentSide2, completedEdges, ant
ialias); | 841 MiterType miter2 = computeMiter(side, adjacentSide2, completedEdges, ant
ialias); |
| 842 bool shouldClip = mitresRequireClipping(mitre1, mitre2, edgeToRender.bor
derStyle(), antialias); | 842 bool shouldClip = mitersRequireClipping(miter1, miter2, edgeToRender.bor
derStyle(), antialias); |
| 843 | 843 |
| 844 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip); | 844 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip); |
| 845 if (shouldClip) { | 845 if (shouldClip) { |
| 846 clipBorderSidePolygon(graphicsContext, side, mitre1, mitre2); | 846 clipBorderSidePolygon(graphicsContext, side, miter1, miter2); |
| 847 | 847 |
| 848 // Mitres are applied via clipping, no need to draw them. | 848 // Miters are applied via clipping, no need to draw them. |
| 849 mitre1 = mitre2 = NoMitre; | 849 miter1 = miter2 = NoMiter; |
| 850 } | 850 } |
| 851 | 851 |
| 852 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec
t.y(), | 852 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec
t.y(), |
| 853 sideRect.maxX(), sideRect.maxY(), side, color, edgeToRender.borderSt
yle(), | 853 sideRect.maxX(), sideRect.maxY(), side, color, edgeToRender.borderSt
yle(), |
| 854 mitre1 != NoMitre ? adjacentEdge1.width : 0, mitre2 != NoMitre ? adj
acentEdge2.width : 0, | 854 miter1 != NoMiter ? adjacentEdge1.width : 0, miter2 != NoMiter ? adj
acentEdge2.width : 0, |
| 855 antialias); | 855 antialias); |
| 856 } | 856 } |
| 857 } | 857 } |
| 858 | 858 |
| 859 void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext, | 859 void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext, |
| 860 const LayoutRect& borderRect, const Path& borderPath, float thickness, float
drawThickness, | 860 const LayoutRect& borderRect, const Path& borderPath, float thickness, float
drawThickness, |
| 861 BoxSide side, Color color, EBorderStyle borderStyle) const | 861 BoxSide side, Color color, EBorderStyle borderStyle) const |
| 862 { | 862 { |
| 863 if (thickness <= 0) | 863 if (thickness <= 0) |
| 864 return; | 864 return; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 999 void BoxBorderPainter::clipBorderSideForComplexInnerPath(GraphicsContext* graphi
csContext, | 999 void BoxBorderPainter::clipBorderSideForComplexInnerPath(GraphicsContext* graphi
csContext, |
| 1000 BoxSide side) const | 1000 BoxSide side) const |
| 1001 { | 1001 { |
| 1002 graphicsContext->clip(calculateSideRectIncludingInner(m_outer, m_edges, side
)); | 1002 graphicsContext->clip(calculateSideRectIncludingInner(m_outer, m_edges, side
)); |
| 1003 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(m_inner, s
ide); | 1003 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(m_inner, s
ide); |
| 1004 if (!adjustedInnerRect.isEmpty()) | 1004 if (!adjustedInnerRect.isEmpty()) |
| 1005 graphicsContext->clipOutRoundedRect(adjustedInnerRect); | 1005 graphicsContext->clipOutRoundedRect(adjustedInnerRect); |
| 1006 } | 1006 } |
| 1007 | 1007 |
| 1008 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext* graphicsContext, B
oxSide side, | 1008 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext* graphicsContext, B
oxSide side, |
| 1009 MitreType firstMitre, MitreType secondMitre) const | 1009 MiterType firstMiter, MiterType secondMiter) const |
| 1010 { | 1010 { |
| 1011 ASSERT(firstMitre != NoMitre || secondMitre != NoMitre); | 1011 ASSERT(firstMiter != NoMiter || secondMiter != NoMiter); |
| 1012 | 1012 |
| 1013 FloatPoint quad[4]; | 1013 FloatPoint quad[4]; |
| 1014 | 1014 |
| 1015 const LayoutRect outerRect(m_outer.rect()); | 1015 const LayoutRect outerRect(m_outer.rect()); |
| 1016 const LayoutRect innerRect(m_inner.rect()); | 1016 const LayoutRect innerRect(m_inner.rect()); |
| 1017 | 1017 |
| 1018 // For each side, create a quad that encompasses all parts of that side that
may draw, | 1018 // For each side, create a quad that encompasses all parts of that side that
may draw, |
| 1019 // including areas inside the innerBorder. | 1019 // including areas inside the innerBorder. |
| 1020 // | 1020 // |
| 1021 // 0----------------3 | 1021 // 0----------------3 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 quad[2].x() - m_inner.radii().bottomRight().width(), | 1140 quad[2].x() - m_inner.radii().bottomRight().width(), |
| 1141 quad[2].y()), | 1141 quad[2].y()), |
| 1142 FloatPoint( | 1142 FloatPoint( |
| 1143 quad[2].x(), | 1143 quad[2].x(), |
| 1144 quad[2].y() - m_inner.radii().bottomRight().height()), | 1144 quad[2].y() - m_inner.radii().bottomRight().height()), |
| 1145 quad[2]); | 1145 quad[2]); |
| 1146 } | 1146 } |
| 1147 break; | 1147 break; |
| 1148 } | 1148 } |
| 1149 | 1149 |
| 1150 if (firstMitre == secondMitre) { | 1150 if (firstMiter == secondMiter) { |
| 1151 graphicsContext->clipPolygon(4, quad, firstMitre == SoftMitre); | 1151 graphicsContext->clipPolygon(4, quad, firstMiter == SoftMiter); |
| 1152 return; | 1152 return; |
| 1153 } | 1153 } |
| 1154 | 1154 |
| 1155 // If antialiasing settings for the first edge and second edge is different, | 1155 // If antialiasing settings for the first edge and second edge is different, |
| 1156 // they have to be addressed separately. We do this by breaking the quad int
o | 1156 // they have to be addressed separately. We do this by breaking the quad int
o |
| 1157 // two parallelograms, made by moving quad[1] and quad[2]. | 1157 // two parallelograms, made by moving quad[1] and quad[2]. |
| 1158 float ax = quad[1].x() - quad[0].x(); | 1158 float ax = quad[1].x() - quad[0].x(); |
| 1159 float ay = quad[1].y() - quad[0].y(); | 1159 float ay = quad[1].y() - quad[0].y(); |
| 1160 float bx = quad[2].x() - quad[1].x(); | 1160 float bx = quad[2].x() - quad[1].x(); |
| 1161 float by = quad[2].y() - quad[1].y(); | 1161 float by = quad[2].y() - quad[1].y(); |
| 1162 float cx = quad[3].x() - quad[2].x(); | 1162 float cx = quad[3].x() - quad[2].x(); |
| 1163 float cy = quad[3].y() - quad[2].y(); | 1163 float cy = quad[3].y() - quad[2].y(); |
| 1164 | 1164 |
| 1165 const static float kEpsilon = 1e-2f; | 1165 const static float kEpsilon = 1e-2f; |
| 1166 float r1, r2; | 1166 float r1, r2; |
| 1167 if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) { | 1167 if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) { |
| 1168 // The quad was actually a triangle. | 1168 // The quad was actually a triangle. |
| 1169 r1 = r2 = 1.0f; | 1169 r1 = r2 = 1.0f; |
| 1170 } else { | 1170 } else { |
| 1171 // Extend parallelogram a bit to hide calculation error | 1171 // Extend parallelogram a bit to hide calculation error |
| 1172 const static float kExtendFill = 1e-2f; | 1172 const static float kExtendFill = 1e-2f; |
| 1173 | 1173 |
| 1174 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill; | 1174 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill; |
| 1175 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill; | 1175 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill; |
| 1176 } | 1176 } |
| 1177 | 1177 |
| 1178 if (firstMitre != NoMitre) { | 1178 if (firstMiter != NoMiter) { |
| 1179 FloatPoint firstQuad[4]; | 1179 FloatPoint firstQuad[4]; |
| 1180 firstQuad[0] = quad[0]; | 1180 firstQuad[0] = quad[0]; |
| 1181 firstQuad[1] = quad[1]; | 1181 firstQuad[1] = quad[1]; |
| 1182 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay); | 1182 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay); |
| 1183 firstQuad[3] = quad[3]; | 1183 firstQuad[3] = quad[3]; |
| 1184 graphicsContext->clipPolygon(4, firstQuad, firstMitre == SoftMitre); | 1184 graphicsContext->clipPolygon(4, firstQuad, firstMiter == SoftMiter); |
| 1185 } | 1185 } |
| 1186 | 1186 |
| 1187 if (secondMitre != NoMitre) { | 1187 if (secondMiter != NoMiter) { |
| 1188 FloatPoint secondQuad[4]; | 1188 FloatPoint secondQuad[4]; |
| 1189 secondQuad[0] = quad[0]; | 1189 secondQuad[0] = quad[0]; |
| 1190 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy)
; | 1190 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy)
; |
| 1191 secondQuad[2] = quad[2]; | 1191 secondQuad[2] = quad[2]; |
| 1192 secondQuad[3] = quad[3]; | 1192 secondQuad[3] = quad[3]; |
| 1193 graphicsContext->clipPolygon(4, secondQuad, secondMitre == SoftMitre); | 1193 graphicsContext->clipPolygon(4, secondQuad, secondMiter == SoftMiter); |
| 1194 } | 1194 } |
| 1195 } | 1195 } |
| 1196 | 1196 |
| 1197 } // namespace blink | 1197 } // namespace blink |
| OLD | NEW |