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

Side by Side Diff: third_party/WebKit/Source/core/paint/BoxBorderPainter.cpp

Issue 2392443009: reflow comments in core/paint (Closed)
Patch Set: Created 4 years, 2 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 unified diff | Download patch
OLDNEW
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 "core/paint/BoxBorderPainter.h" 5 #include "core/paint/BoxBorderPainter.h"
6 6
7 #include "core/paint/BoxPainter.h" 7 #include "core/paint/BoxPainter.h"
8 #include "core/paint/ObjectPainter.h" 8 #include "core/paint/ObjectPainter.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"
(...skipping 19 matching lines...) Expand all
30 30
31 inline BorderEdgeFlag edgeFlagForSide(BoxSide side) { 31 inline BorderEdgeFlag edgeFlagForSide(BoxSide side) {
32 return static_cast<BorderEdgeFlag>(1 << side); 32 return static_cast<BorderEdgeFlag>(1 << side);
33 } 33 }
34 34
35 inline bool includesEdge(BorderEdgeFlags flags, BoxSide side) { 35 inline bool includesEdge(BorderEdgeFlags flags, BoxSide side) {
36 return flags & edgeFlagForSide(side); 36 return flags & edgeFlagForSide(side);
37 } 37 }
38 38
39 inline bool includesAdjacentEdges(BorderEdgeFlags flags) { 39 inline bool includesAdjacentEdges(BorderEdgeFlags flags) {
40 // The set includes adjacent edges iff it contains at least one horizontal and one vertical edge. 40 // The set includes adjacent edges iff it contains at least one horizontal and
41 // one vertical edge.
41 return (flags & (TopBorderEdge | BottomBorderEdge)) && 42 return (flags & (TopBorderEdge | BottomBorderEdge)) &&
42 (flags & (LeftBorderEdge | RightBorderEdge)); 43 (flags & (LeftBorderEdge | RightBorderEdge));
43 } 44 }
44 45
45 inline bool styleRequiresClipPolygon(EBorderStyle style) { 46 inline bool styleRequiresClipPolygon(EBorderStyle style) {
46 // These are drawn with a stroke, so we have to clip to get corner miters. 47 // These are drawn with a stroke, so we have to clip to get corner miters.
47 return style == BorderStyleDotted || style == BorderStyleDashed; 48 return style == BorderStyleDotted || style == BorderStyleDashed;
48 } 49 }
49 50
50 inline bool borderStyleFillsBorderArea(EBorderStyle style) { 51 inline bool borderStyleFillsBorderArea(EBorderStyle style) {
51 return !(style == BorderStyleDotted || style == BorderStyleDashed || 52 return !(style == BorderStyleDotted || style == BorderStyleDashed ||
52 style == BorderStyleDouble); 53 style == BorderStyleDouble);
53 } 54 }
54 55
55 inline bool borderStyleHasInnerDetail(EBorderStyle style) { 56 inline bool borderStyleHasInnerDetail(EBorderStyle style) {
56 return style == BorderStyleGroove || style == BorderStyleRidge || 57 return style == BorderStyleGroove || style == BorderStyleRidge ||
57 style == BorderStyleDouble; 58 style == BorderStyleDouble;
58 } 59 }
59 60
60 inline bool borderStyleIsDottedOrDashed(EBorderStyle style) { 61 inline bool borderStyleIsDottedOrDashed(EBorderStyle style) {
61 return style == BorderStyleDotted || style == BorderStyleDashed; 62 return style == BorderStyleDotted || style == BorderStyleDashed;
62 } 63 }
63 64
64 // BorderStyleOutset darkens the bottom and right (and maybe lightens the top an d left) 65 // BorderStyleOutset darkens the bottom and right (and maybe lightens the top
65 // BorderStyleInset darkens the top and left (and maybe lightens the bottom and right) 66 // and left) BorderStyleInset darkens the top and left (and maybe lightens the
67 // bottom and right).
66 inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style, 68 inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style,
67 BoxSide side, 69 BoxSide side,
68 BoxSide adjacentSide) { 70 BoxSide adjacentSide) {
69 // These styles match at the top/left and bottom/right. 71 // These styles match at the top/left and bottom/right.
70 if (style == BorderStyleInset || style == BorderStyleGroove || 72 if (style == BorderStyleInset || style == BorderStyleGroove ||
71 style == BorderStyleRidge || style == BorderStyleOutset) { 73 style == BorderStyleRidge || style == BorderStyleOutset) {
72 const BorderEdgeFlags topRightFlags = 74 const BorderEdgeFlags topRightFlags =
73 edgeFlagForSide(BSTop) | edgeFlagForSide(BSRight); 75 edgeFlagForSide(BSTop) | edgeFlagForSide(BSRight);
74 const BorderEdgeFlags bottomLeftFlags = 76 const BorderEdgeFlags bottomLeftFlags =
75 edgeFlagForSide(BSBottom) | edgeFlagForSide(BSLeft); 77 edgeFlagForSide(BSBottom) | edgeFlagForSide(BSLeft);
(...skipping 19 matching lines...) Expand all
95 } 97 }
96 98
97 inline bool borderWillArcInnerEdge(const FloatSize& firstRadius, 99 inline bool borderWillArcInnerEdge(const FloatSize& firstRadius,
98 const FloatSize& secondRadius) { 100 const FloatSize& secondRadius) {
99 return !firstRadius.isZero() || !secondRadius.isZero(); 101 return !firstRadius.isZero() || !secondRadius.isZero();
100 } 102 }
101 103
102 inline bool willOverdraw(BoxSide side, 104 inline bool willOverdraw(BoxSide side,
103 EBorderStyle style, 105 EBorderStyle style,
104 BorderEdgeFlags completedEdges) { 106 BorderEdgeFlags completedEdges) {
105 // If we're done with this side, it will obviously not overdraw any portion of the current edge. 107 // If we're done with this side, it will obviously not overdraw any portion of
108 // the current edge.
106 if (includesEdge(completedEdges, side)) 109 if (includesEdge(completedEdges, side))
107 return false; 110 return false;
108 111
109 // The side is still to be drawn. It overdraws the current edge iff it has a s olid fill style. 112 // The side is still to be drawn. It overdraws the current edge iff it has a
113 // solid fill style.
110 return borderStyleFillsBorderArea(style); 114 return borderStyleFillsBorderArea(style);
111 } 115 }
112 116
113 inline bool borderStylesRequireMiter(BoxSide side, 117 inline bool borderStylesRequireMiter(BoxSide side,
114 BoxSide adjacentSide, 118 BoxSide adjacentSide,
115 EBorderStyle style, 119 EBorderStyle style,
116 EBorderStyle adjacentStyle) { 120 EBorderStyle adjacentStyle) {
117 if (style == BorderStyleDouble || adjacentStyle == BorderStyleDouble || 121 if (style == BorderStyleDouble || adjacentStyle == BorderStyleDouble ||
118 adjacentStyle == BorderStyleGroove || adjacentStyle == BorderStyleRidge) 122 adjacentStyle == BorderStyleGroove || adjacentStyle == BorderStyleRidge)
119 return true; 123 return true;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 sideRect.shiftXEdgeTo(sideRect.maxX() - width); 174 sideRect.shiftXEdgeTo(sideRect.maxX() - width);
171 break; 175 break;
172 } 176 }
173 177
174 return sideRect; 178 return sideRect;
175 } 179 }
176 180
177 FloatRoundedRect calculateAdjustedInnerBorder( 181 FloatRoundedRect calculateAdjustedInnerBorder(
178 const FloatRoundedRect& innerBorder, 182 const FloatRoundedRect& innerBorder,
179 BoxSide side) { 183 BoxSide side) {
180 // Expand the inner border as necessary to make it a rounded rect (i.e. radii contained within each edge). 184 // Expand the inner border as necessary to make it a rounded rect (i.e. radii
181 // This function relies on the fact we only get radii not contained within eac h edge if one of the radii 185 // contained within each edge). This function relies on the fact we only get
182 // for an edge is zero, so we can shift the arc towards the zero radius corner . 186 // radii not contained within each edge if one of the radii for an edge is
187 // zero, so we can shift the arc towards the zero radius corner.
183 FloatRoundedRect::Radii newRadii = innerBorder.getRadii(); 188 FloatRoundedRect::Radii newRadii = innerBorder.getRadii();
184 FloatRect newRect = innerBorder.rect(); 189 FloatRect newRect = innerBorder.rect();
185 190
186 float overshoot; 191 float overshoot;
187 float maxRadii; 192 float maxRadii;
188 193
189 switch (side) { 194 switch (side) {
190 case BSTop: 195 case BSTop:
191 overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - 196 overshoot = newRadii.topLeft().width() + newRadii.topRight().width() -
192 newRect.width(); 197 newRect.width();
193 // FIXME: once we start pixel-snapping rounded rects after this point, the overshoot concept 198 // FIXME: once we start pixel-snapping rounded rects after this point, the
194 // should disappear. 199 // overshoot concept should disappear.
195 if (overshoot > 0.1) { 200 if (overshoot > 0.1) {
196 newRect.setWidth(newRect.width() + overshoot); 201 newRect.setWidth(newRect.width() + overshoot);
197 if (!newRadii.topLeft().width()) 202 if (!newRadii.topLeft().width())
198 newRect.move(-overshoot, 0); 203 newRect.move(-overshoot, 0);
199 } 204 }
200 newRadii.setBottomLeft(FloatSize(0, 0)); 205 newRadii.setBottomLeft(FloatSize(0, 0));
201 newRadii.setBottomRight(FloatSize(0, 0)); 206 newRadii.setBottomRight(FloatSize(0, 0));
202 maxRadii = 207 maxRadii =
203 std::max(newRadii.topLeft().height(), newRadii.topRight().height()); 208 std::max(newRadii.topLeft().height(), newRadii.topRight().height());
204 if (maxRadii > newRect.height()) 209 if (maxRadii > newRect.height())
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 context.setShouldAntialias(false); 294 context.setShouldAntialias(false);
290 } 295 }
291 296
292 void drawBleedAdjustedDRRect(GraphicsContext& context, 297 void drawBleedAdjustedDRRect(GraphicsContext& context,
293 BackgroundBleedAvoidance bleedAvoidance, 298 BackgroundBleedAvoidance bleedAvoidance,
294 const FloatRoundedRect& outer, 299 const FloatRoundedRect& outer,
295 const FloatRoundedRect& inner, 300 const FloatRoundedRect& inner,
296 Color color) { 301 Color color) {
297 switch (bleedAvoidance) { 302 switch (bleedAvoidance) {
298 case BackgroundBleedClipLayer: { 303 case BackgroundBleedClipLayer: {
299 // BackgroundBleedClipLayer clips the outer rrect for the whole layer. Bas ed on this, 304 // BackgroundBleedClipLayer clips the outer rrect for the whole layer.
300 // we can avoid background bleeding by filling the *outside* of inner rrec t, all the 305 // Based on this, we can avoid background bleeding by filling the
301 // way to the layer bounds (enclosing int rect for the clip, in device spa ce). 306 // *outside* of inner rrect, all the way to the layer bounds (enclosing
307 // int rect for the clip, in device space).
302 ASSERT(outer.isRounded()); 308 ASSERT(outer.isRounded());
303 309
304 SkPath path; 310 SkPath path;
305 path.addRRect(inner); 311 path.addRRect(inner);
306 path.setFillType(SkPath::kInverseWinding_FillType); 312 path.setFillType(SkPath::kInverseWinding_FillType);
307 313
308 SkPaint paint; 314 SkPaint paint;
309 paint.setColor(color.rgb()); 315 paint.setColor(color.rgb());
310 paint.setStyle(SkPaint::kFill_Style); 316 paint.setStyle(SkPaint::kFill_Style);
311 paint.setAntiAlias(true); 317 paint.setAntiAlias(true);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 static_assert(BorderStyleDotted == 6, "unexpected EBorderStyle value"); 349 static_assert(BorderStyleDotted == 6, "unexpected EBorderStyle value");
344 static_assert(BorderStyleDashed == 7, "unexpected EBorderStyle value"); 350 static_assert(BorderStyleDashed == 7, "unexpected EBorderStyle value");
345 static_assert(BorderStyleSolid == 8, "unexpected EBorderStyle value"); 351 static_assert(BorderStyleSolid == 8, "unexpected EBorderStyle value");
346 static_assert(BorderStyleDouble == 9, "unexpected EBorderStyle value"); 352 static_assert(BorderStyleDouble == 9, "unexpected EBorderStyle value");
347 353
348 static_assert(BSTop == 0, "unexpected BoxSide value"); 354 static_assert(BSTop == 0, "unexpected BoxSide value");
349 static_assert(BSRight == 1, "unexpected BoxSide value"); 355 static_assert(BSRight == 1, "unexpected BoxSide value");
350 static_assert(BSBottom == 2, "unexpected BoxSide value"); 356 static_assert(BSBottom == 2, "unexpected BoxSide value");
351 static_assert(BSLeft == 3, "unexpected BoxSide value"); 357 static_assert(BSLeft == 3, "unexpected BoxSide value");
352 358
353 // Style-based paint order: non-solid edges (dashed/dotted/double) are painted b efore 359 // Style-based paint order: non-solid edges (dashed/dotted/double) are painted
354 // solid edges (inset/outset/groove/ridge/solid) to maximize overdraw opportunit ies. 360 // before solid edges (inset/outset/groove/ridge/solid) to maximize overdraw
361 // opportunities.
355 const unsigned kStylePriority[] = { 362 const unsigned kStylePriority[] = {
356 0 /* BorderStyleNone */, 0 /* BorderStyleHidden */, 363 0 /* BorderStyleNone */, 0 /* BorderStyleHidden */,
357 2 /* BorderStyleInset */, 2 /* BorderStyleGroove */, 364 2 /* BorderStyleInset */, 2 /* BorderStyleGroove */,
358 2 /* BorderStyleOutset */, 2 /* BorderStyleRidge */, 365 2 /* BorderStyleOutset */, 2 /* BorderStyleRidge */,
359 1 /* BorderStyleDotted */, 1 /* BorderStyleDashed */, 366 1 /* BorderStyleDotted */, 1 /* BorderStyleDashed */,
360 3 /* BorderStyleSolid */, 1 /* BorderStyleDouble */ 367 3 /* BorderStyleSolid */, 1 /* BorderStyleDouble */
361 }; 368 };
362 369
363 // Given the same style, prefer drawing in non-adjacent order to minimize the nu mber of sides 370 // Given the same style, prefer drawing in non-adjacent order to minimize the
364 // which require miters. 371 // number of sides which require miters.
365 const unsigned kSidePriority[] = { 372 const unsigned kSidePriority[] = {
366 0, /* BSTop */ 373 0, /* BSTop */
367 2, /* BSRight */ 374 2, /* BSRight */
368 1, /* BSBottom */ 375 1, /* BSBottom */
369 3, /* BSLeft */ 376 3, /* BSLeft */
370 }; 377 };
371 378
372 // Edges sharing the same opacity. Stores both a side list and an edge bitfield to support 379 // Edges sharing the same opacity. Stores both a side list and an edge bitfield
373 // constant time iteration + membership tests. 380 // to support constant time iteration + membership tests.
374 struct OpacityGroup { 381 struct OpacityGroup {
375 OpacityGroup(unsigned alpha) : edgeFlags(0), alpha(alpha) {} 382 OpacityGroup(unsigned alpha) : edgeFlags(0), alpha(alpha) {}
376 383
377 Vector<BoxSide, 4> sides; 384 Vector<BoxSide, 4> sides;
378 BorderEdgeFlags edgeFlags; 385 BorderEdgeFlags edgeFlags;
379 unsigned alpha; 386 unsigned alpha;
380 }; 387 };
381 388
382 void clipQuad(GraphicsContext& context, 389 void clipQuad(GraphicsContext& context,
383 const FloatPoint quad[], 390 const FloatPoint quad[],
(...skipping 17 matching lines...) Expand all
401 408
402 // First, collect all visible sides. 409 // First, collect all visible sides.
403 for (unsigned i = borderPainter.m_firstVisibleEdge; i < 4; ++i) { 410 for (unsigned i = borderPainter.m_firstVisibleEdge; i < 4; ++i) {
404 BoxSide side = static_cast<BoxSide>(i); 411 BoxSide side = static_cast<BoxSide>(i);
405 412
406 if (includesEdge(borderPainter.m_visibleEdgeSet, side)) 413 if (includesEdge(borderPainter.m_visibleEdgeSet, side))
407 sortedSides.append(side); 414 sortedSides.append(side);
408 } 415 }
409 ASSERT(!sortedSides.isEmpty()); 416 ASSERT(!sortedSides.isEmpty());
410 417
411 // Then sort them in paint order, based on three (prioritized) criteria: alp ha, style, side. 418 // Then sort them in paint order, based on three (prioritized) criteria:
419 // alpha, style, side.
412 std::sort( 420 std::sort(
413 sortedSides.begin(), sortedSides.end(), 421 sortedSides.begin(), sortedSides.end(),
414 [&borderPainter](BoxSide a, BoxSide b) -> bool { 422 [&borderPainter](BoxSide a, BoxSide b) -> bool {
415 const BorderEdge& edgeA = borderPainter.m_edges[a]; 423 const BorderEdge& edgeA = borderPainter.m_edges[a];
416 const BorderEdge& edgeB = borderPainter.m_edges[b]; 424 const BorderEdge& edgeB = borderPainter.m_edges[b];
417 425
418 const unsigned alphaA = edgeA.color.alpha(); 426 const unsigned alphaA = edgeA.color.alpha();
419 const unsigned alphaB = edgeB.color.alpha(); 427 const unsigned alphaB = edgeB.color.alpha();
420 if (alphaA != alphaB) 428 if (alphaA != alphaB)
421 return alphaA < alphaB; 429 return alphaA < alphaB;
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 } 524 }
517 } else { 525 } else {
518 // 4-side, double border => 2x drawDRRect() 526 // 4-side, double border => 2x drawDRRect()
519 ASSERT(firstEdge().borderStyle() == BorderStyleDouble); 527 ASSERT(firstEdge().borderStyle() == BorderStyleDouble);
520 drawDoubleBorder(context, borderRect); 528 drawDoubleBorder(context, borderRect);
521 } 529 }
522 530
523 return true; 531 return true;
524 } 532 }
525 533
526 // This is faster than the normal complex border path only if it avoids creati ng transparency 534 // This is faster than the normal complex border path only if it avoids
527 // layers (when the border is translucent). 535 // creating transparency layers (when the border is translucent).
528 if (firstEdge().borderStyle() == BorderStyleSolid && !m_outer.isRounded() && 536 if (firstEdge().borderStyle() == BorderStyleSolid && !m_outer.isRounded() &&
529 m_hasAlpha) { 537 m_hasAlpha) {
530 ASSERT(m_visibleEdgeSet != AllBorderEdges); 538 ASSERT(m_visibleEdgeSet != AllBorderEdges);
531 // solid, rectangular border => one drawPath() 539 // solid, rectangular border => one drawPath()
532 Path path; 540 Path path;
533 path.setWindRule(RULE_NONZERO); 541 path.setWindRule(RULE_NONZERO);
534 542
535 for (int i = BSTop; i <= BSLeft; ++i) { 543 for (int i = BSTop; i <= BSLeft; ++i) {
536 const BorderEdge& currEdge = m_edges[i]; 544 const BorderEdge& currEdge = m_edges[i];
537 if (currEdge.shouldRender()) 545 if (currEdge.shouldRender())
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 return; 649 return;
642 650
643 GraphicsContext& graphicsContext = info.context; 651 GraphicsContext& graphicsContext = info.context;
644 652
645 if (paintBorderFastPath(graphicsContext, rect)) 653 if (paintBorderFastPath(graphicsContext, rect))
646 return; 654 return;
647 655
648 bool clipToOuterBorder = m_outer.isRounded(); 656 bool clipToOuterBorder = m_outer.isRounded();
649 GraphicsContextStateSaver stateSaver(graphicsContext, clipToOuterBorder); 657 GraphicsContextStateSaver stateSaver(graphicsContext, clipToOuterBorder);
650 if (clipToOuterBorder) { 658 if (clipToOuterBorder) {
651 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already appl ied. 659 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already
660 // applied.
652 if (!bleedAvoidanceIsClipping(m_bleedAvoidance)) 661 if (!bleedAvoidanceIsClipping(m_bleedAvoidance))
653 graphicsContext.clipRoundedRect(m_outer); 662 graphicsContext.clipRoundedRect(m_outer);
654 663
655 if (m_inner.isRenderable() && !m_inner.isEmpty()) 664 if (m_inner.isRenderable() && !m_inner.isEmpty())
656 graphicsContext.clipOutRoundedRect(m_inner); 665 graphicsContext.clipOutRoundedRect(m_inner);
657 } 666 }
658 667
659 const ComplexBorderInfo borderInfo(*this, true); 668 const ComplexBorderInfo borderInfo(*this, true);
660 paintOpacityGroup(graphicsContext, borderInfo, 0, 1); 669 paintOpacityGroup(graphicsContext, borderInfo, 0, 1);
661 } 670 }
662 671
663 // In order to maximize the use of overdraw as a corner seam avoidance technique , we draw 672 // In order to maximize the use of overdraw as a corner seam avoidance
664 // translucent border sides using the following algorithm: 673 // technique, we draw translucent border sides using the following algorithm:
665 // 674 //
666 // 1) cluster sides sharing the same opacity into "opacity groups" [ComplexBor derInfo] 675 // 1) cluster sides sharing the same opacity into "opacity groups"
676 // [ComplexBorderInfo]
667 // 2) sort groups in increasing opacity order [ComplexBorderInfo] 677 // 2) sort groups in increasing opacity order [ComplexBorderInfo]
668 // 3) reverse-iterate over groups (decreasing opacity order), pushing nested t ransparency 678 // 3) reverse-iterate over groups (decreasing opacity order), pushing nested
669 // layers with adjusted/relative opacity [paintOpacityGroup] 679 // transparency layers with adjusted/relative opacity [paintOpacityGroup]
670 // 4) iterate over groups (increasing opacity order), painting actual group co ntents and 680 // 4) iterate over groups (increasing opacity order), painting actual group
671 // then ending their corresponding transparency layer [paintOpacityGroup] 681 // contents and then ending their corresponding transparency layer
682 // [paintOpacityGroup]
672 // 683 //
673 // Layers are created in decreasing opacity order (top -> bottom), while actual border sides are 684 // Layers are created in decreasing opacity order (top -> bottom), while actual
674 // drawn in increasing opacity order (bottom -> top). At each level, opacity is adjusted to acount 685 // border sides are drawn in increasing opacity order (bottom -> top). At each
675 // for accumulated/ancestor layer alpha. Because opacity is applied via layers, the actual draw 686 // level, opacity is adjusted to acount for accumulated/ancestor layer alpha.
676 // paint is opaque. 687 // Because opacity is applied via layers, the actual draw paint is opaque.
677 // 688 //
678 // As an example, let's consider a border with the following sides/opacities: 689 // As an example, let's consider a border with the following sides/opacities:
679 // 690 //
680 // top: 1.0 691 // top: 1.0
681 // right: 0.25 692 // right: 0.25
682 // bottom: 0.5 693 // bottom: 0.5
683 // left: 0.25 694 // left: 0.25
684 // 695 //
685 // These are grouped and sorted in ComplexBorderInfo as follows: 696 // These are grouped and sorted in ComplexBorderInfo as follows:
686 // 697 //
687 // group[0]: { alpha: 1.0, sides: top } 698 // group[0]: { alpha: 1.0, sides: top }
688 // group[1]: { alpha: 0.5, sides: bottom } 699 // group[1]: { alpha: 0.5, sides: bottom }
689 // group[2]: { alpha: 0.25, sides: right, left } 700 // group[2]: { alpha: 0.25, sides: right, left }
690 // 701 //
691 // Applying the algorithm yields the following paint sequence: 702 // Applying the algorithm yields the following paint sequence:
692 // 703 //
693 // // no layer needed for group 0 (alpha == 1) 704 // // no layer needed for group 0 (alpha = 1)
694 // beginLayer(0.5) // layer for group 1 705 // beginLayer(0.5) // layer for group 1
695 // beginLayer(0.5) // layer for group 2 (effective opacity: 0.5 * 0.5 == 0.25) 706 // beginLayer(0.5) // layer for group 2 (alpha: 0.5 * 0.5 = 0.25)
696 // paintSides(right, left) // paint group 2 707 // paintSides(right, left) // paint group 2
697 // endLayer 708 // endLayer
698 // paintSides(bottom) // paint group 1 709 // paintSides(bottom) // paint group 1
699 // endLayer 710 // endLayer
700 // paintSides(top) // paint group 0 711 // paintSides(top) // paint group 0
701 // 712 //
702 // Note that we're always drawing using opaque paints on top of less-opaque cont ent - hence 713 // Note that we're always drawing using opaque paints on top of less-opaque
703 // we can use overdraw to mask portions of the previous sides. 714 // content - hence we can use overdraw to mask portions of the previous sides.
704 // 715 //
705 BorderEdgeFlags BoxBorderPainter::paintOpacityGroup( 716 BorderEdgeFlags BoxBorderPainter::paintOpacityGroup(
706 GraphicsContext& context, 717 GraphicsContext& context,
707 const ComplexBorderInfo& borderInfo, 718 const ComplexBorderInfo& borderInfo,
708 unsigned index, 719 unsigned index,
709 float effectiveOpacity) const { 720 float effectiveOpacity) const {
710 ASSERT(effectiveOpacity > 0 && effectiveOpacity <= 1); 721 ASSERT(effectiveOpacity > 0 && effectiveOpacity <= 1);
711 722
712 const size_t opacityGroupCount = borderInfo.opacityGroups.size(); 723 const size_t opacityGroupCount = borderInfo.opacityGroups.size();
713 724
714 // For overdraw logic purposes, treat missing/transparent edges as completed. 725 // For overdraw logic purposes, treat missing/transparent edges as completed.
715 if (index >= opacityGroupCount) 726 if (index >= opacityGroupCount)
716 return ~m_visibleEdgeSet; 727 return ~m_visibleEdgeSet;
717 728
718 // Groups are sorted in increasing opacity order, but we need to create layers in 729 // Groups are sorted in increasing opacity order, but we need to create layers
719 // decreasing opacity order - hence the reverse iteration. 730 // in decreasing opacity order - hence the reverse iteration.
720 const OpacityGroup& group = 731 const OpacityGroup& group =
721 borderInfo.opacityGroups[opacityGroupCount - index - 1]; 732 borderInfo.opacityGroups[opacityGroupCount - index - 1];
722 733
723 // Adjust this group's paint opacity to account for ancestor transparency laye rs 734 // Adjust this group's paint opacity to account for ancestor transparency
724 // (needed in case we avoid creating a layer below). 735 // layers (needed in case we avoid creating a layer below).
725 unsigned paintAlpha = group.alpha / effectiveOpacity; 736 unsigned paintAlpha = group.alpha / effectiveOpacity;
726 ASSERT(paintAlpha <= 255); 737 ASSERT(paintAlpha <= 255);
727 738
728 // For the last (bottom) group, we can skip the layer even in the presence of opacity iff 739 // For the last (bottom) group, we can skip the layer even in the presence of
729 // it contains no adjecent edges (no in-group overdraw possibility). 740 // opacity iff it contains no adjecent edges (no in-group overdraw
741 // possibility).
730 bool needsLayer = 742 bool needsLayer =
731 group.alpha != 255 && (includesAdjacentEdges(group.edgeFlags) || 743 group.alpha != 255 && (includesAdjacentEdges(group.edgeFlags) ||
732 (index + 1 < borderInfo.opacityGroups.size())); 744 (index + 1 < borderInfo.opacityGroups.size()));
733 745
734 if (needsLayer) { 746 if (needsLayer) {
735 const float groupOpacity = static_cast<float>(group.alpha) / 255; 747 const float groupOpacity = static_cast<float>(group.alpha) / 255;
736 ASSERT(groupOpacity < effectiveOpacity); 748 ASSERT(groupOpacity < effectiveOpacity);
737 749
738 context.beginLayer(groupOpacity / effectiveOpacity); 750 context.beginLayer(groupOpacity / effectiveOpacity);
739 effectiveOpacity = groupOpacity; 751 effectiveOpacity = groupOpacity;
740 752
741 // Group opacity is applied via a layer => we draw the members using opaque paint. 753 // Group opacity is applied via a layer => we draw the members using opaque
754 // paint.
742 paintAlpha = 255; 755 paintAlpha = 255;
743 } 756 }
744 757
745 // Recursion may seem unpalatable here, but 758 // Recursion may seem unpalatable here, but
746 // a) it has an upper bound of 4 759 // a) it has an upper bound of 4
747 // b) only triggers at all when mixing border sides with different opacities 760 // b) only triggers at all when mixing border sides with different opacities
748 // c) it allows us to express the layer nesting algorithm more naturally 761 // c) it allows us to express the layer nesting algorithm more naturally
749 BorderEdgeFlags completedEdges = 762 BorderEdgeFlags completedEdges =
750 paintOpacityGroup(context, borderInfo, index + 1, effectiveOpacity); 763 paintOpacityGroup(context, borderInfo, index + 1, effectiveOpacity);
751 764
752 // Paint the actual group edges with an alpha adjusted to account for ancensto r layers opacity. 765 // Paint the actual group edges with an alpha adjusted to account for
766 // ancenstor layers opacity.
753 for (BoxSide side : group.sides) { 767 for (BoxSide side : group.sides) {
754 paintSide(context, borderInfo, side, paintAlpha, completedEdges); 768 paintSide(context, borderInfo, side, paintAlpha, completedEdges);
755 completedEdges |= edgeFlagForSide(side); 769 completedEdges |= edgeFlagForSide(side);
756 } 770 }
757 771
758 if (needsLayer) 772 if (needsLayer)
759 context.endLayer(); 773 context.endLayer();
760 774
761 return completedEdges; 775 return completedEdges;
762 } 776 }
763 777
764 void BoxBorderPainter::paintSide(GraphicsContext& context, 778 void BoxBorderPainter::paintSide(GraphicsContext& context,
765 const ComplexBorderInfo& borderInfo, 779 const ComplexBorderInfo& borderInfo,
766 BoxSide side, 780 BoxSide side,
767 unsigned alpha, 781 unsigned alpha,
768 BorderEdgeFlags completedEdges) const { 782 BorderEdgeFlags completedEdges) const {
769 const BorderEdge& edge = m_edges[side]; 783 const BorderEdge& edge = m_edges[side];
770 ASSERT(edge.shouldRender()); 784 ASSERT(edge.shouldRender());
771 const Color color(edge.color.red(), edge.color.green(), edge.color.blue(), 785 const Color color(edge.color.red(), edge.color.green(), edge.color.blue(),
772 alpha); 786 alpha);
773 787
774 FloatRect sideRect = m_outer.rect(); 788 FloatRect sideRect = m_outer.rect();
775 const Path* path = nullptr; 789 const Path* path = nullptr;
776 790
777 // TODO(fmalita): find a way to consolidate these without sacrificing readabil ity. 791 // TODO(fmalita): find a way to consolidate these without sacrificing
792 // readability.
778 switch (side) { 793 switch (side) {
779 case BSTop: { 794 case BSTop: {
780 bool usePath = m_isRounded && 795 bool usePath = m_isRounded &&
781 (borderStyleHasInnerDetail(edge.borderStyle()) || 796 (borderStyleHasInnerDetail(edge.borderStyle()) ||
782 borderWillArcInnerEdge(m_inner.getRadii().topLeft(), 797 borderWillArcInnerEdge(m_inner.getRadii().topLeft(),
783 m_inner.getRadii().topRight())); 798 m_inner.getRadii().topRight()));
784 if (usePath) 799 if (usePath)
785 path = &borderInfo.roundedBorderPath; 800 path = &borderInfo.roundedBorderPath;
786 else 801 else
787 sideRect.setHeight(edge.width); 802 sideRect.setHeight(edge.width);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 const BorderEdge& adjacentEdge = m_edges[adjacentSide]; 860 const BorderEdge& adjacentEdge = m_edges[adjacentSide];
846 861
847 // No miters for missing edges. 862 // No miters for missing edges.
848 if (!adjacentEdge.isPresent) 863 if (!adjacentEdge.isPresent)
849 return NoMiter; 864 return NoMiter;
850 865
851 // The adjacent edge will overdraw this corner, resulting in a correct miter. 866 // The adjacent edge will overdraw this corner, resulting in a correct miter.
852 if (willOverdraw(adjacentSide, adjacentEdge.borderStyle(), completedEdges)) 867 if (willOverdraw(adjacentSide, adjacentEdge.borderStyle(), completedEdges))
853 return NoMiter; 868 return NoMiter;
854 869
855 // Color transitions require miters. Use miters compatible with the AA drawing mode to avoid 870 // Color transitions require miters. Use miters compatible with the AA drawing
856 // introducing extra clips. 871 // mode to avoid introducing extra clips.
857 if (!colorsMatchAtCorner(side, adjacentSide, m_edges)) 872 if (!colorsMatchAtCorner(side, adjacentSide, m_edges))
858 return antialias ? SoftMiter : HardMiter; 873 return antialias ? SoftMiter : HardMiter;
859 874
860 // Non-anti-aliased miters ensure correct same-color seaming when required by style. 875 // Non-anti-aliased miters ensure correct same-color seaming when required by
876 // style.
861 if (borderStylesRequireMiter(side, adjacentSide, m_edges[side].borderStyle(), 877 if (borderStylesRequireMiter(side, adjacentSide, m_edges[side].borderStyle(),
862 adjacentEdge.borderStyle())) 878 adjacentEdge.borderStyle()))
863 return HardMiter; 879 return HardMiter;
864 880
865 // Overdraw the adjacent edge when the colors match and we have no style restr ictions. 881 // Overdraw the adjacent edge when the colors match and we have no style
882 // restrictions.
866 return NoMiter; 883 return NoMiter;
867 } 884 }
868 885
869 bool BoxBorderPainter::mitersRequireClipping(MiterType miter1, 886 bool BoxBorderPainter::mitersRequireClipping(MiterType miter1,
870 MiterType miter2, 887 MiterType miter2,
871 EBorderStyle style, 888 EBorderStyle style,
872 bool antialias) { 889 bool antialias) {
873 // Clipping is required if any of the present miters doesn't match the current AA mode. 890 // Clipping is required if any of the present miters doesn't match the current
891 // AA mode.
874 bool shouldClip = antialias ? miter1 == HardMiter || miter2 == HardMiter 892 bool shouldClip = antialias ? miter1 == HardMiter || miter2 == HardMiter
875 : miter1 == SoftMiter || miter2 == SoftMiter; 893 : miter1 == SoftMiter || miter2 == SoftMiter;
876 894
877 // Some styles require clipping for any type of miter. 895 // Some styles require clipping for any type of miter.
878 shouldClip = shouldClip || ((miter1 != NoMiter || miter2 != NoMiter) && 896 shouldClip = shouldClip || ((miter1 != NoMiter || miter2 != NoMiter) &&
879 styleRequiresClipPolygon(style)); 897 styleRequiresClipPolygon(style));
880 898
881 return shouldClip; 899 return shouldClip;
882 } 900 }
883 901
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 graphicsContext.setStrokeColor(color); 979 graphicsContext.setStrokeColor(color);
962 980
963 // The stroke is doubled here because the provided path is the 981 // The stroke is doubled here because the provided path is the
964 // outside edge of the border so half the stroke is clipped off. 982 // outside edge of the border so half the stroke is clipped off.
965 // The extra multiplier is so that the clipping mask can antialias 983 // The extra multiplier is so that the clipping mask can antialias
966 // the edges to prevent jaggies. 984 // the edges to prevent jaggies.
967 graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f); 985 graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f);
968 graphicsContext.setStrokeStyle( 986 graphicsContext.setStrokeStyle(
969 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke); 987 borderStyle == BorderStyleDashed ? DashedStroke : DottedStroke);
970 988
971 // If the number of dashes that fit in the path is odd and non-integral th en we 989 // If the number of dashes that fit in the path is odd and non-integral
972 // will have an awkwardly-sized dash at the end of the path. To try to avo id that 990 // then we will have an awkwardly-sized dash at the end of the path. To
973 // here, we simply make the whitespace dashes ever so slightly bigger. 991 // try to avoid that here, we simply make the whitespace dashes ever so
974 // FIXME: This could be even better if we tried to manipulate the dash off set 992 // slightly bigger.
975 // and possibly the gapLength to get the corners dash-symmetrical. 993 // FIXME: This could be even better if we tried to manipulate the dash
994 // offset and possibly the gapLength to get the corners dash-symmetrical.
976 float dashLength = 995 float dashLength =
977 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f); 996 thickness * ((borderStyle == BorderStyleDashed) ? 3.0f : 1.0f);
978 float gapLength = dashLength; 997 float gapLength = dashLength;
979 float numberOfDashes = borderPath.length() / dashLength; 998 float numberOfDashes = borderPath.length() / dashLength;
980 // Don't try to show dashes if we have less than 2 dashes + 2 gaps. 999 // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
981 // FIXME: should do this test per side. 1000 // FIXME: should do this test per side.
982 if (numberOfDashes >= 4) { 1001 if (numberOfDashes >= 4) {
983 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); 1002 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
984 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes); 1003 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes);
985 if (!evenNumberOfFullDashes && !integralNumberOfDashes) { 1004 if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
986 float numberOfGaps = numberOfDashes / 2; 1005 float numberOfGaps = numberOfDashes / 2;
987 gapLength += (dashLength / numberOfGaps); 1006 gapLength += (dashLength / numberOfGaps);
988 } 1007 }
989 1008
990 DashArray lineDash; 1009 DashArray lineDash;
991 lineDash.append(dashLength); 1010 lineDash.append(dashLength);
992 lineDash.append(gapLength); 1011 lineDash.append(gapLength);
993 graphicsContext.setLineDash(lineDash, dashLength); 1012 graphicsContext.setLineDash(lineDash, dashLength);
994 } 1013 }
995 1014
996 // FIXME: stroking the border path causes issues with tight corners: 1015 // FIXME: stroking the border path causes issues with tight corners:
997 // https://bugs.webkit.org/show_bug.cgi?id=58711 1016 // https://bugs.webkit.org/show_bug.cgi?id=58711
998 // Also, to get the best appearance we should stroke a path between the tw o borders. 1017 // Also, to get the best appearance we should stroke a path between the
1018 // two borders.
999 graphicsContext.strokePath(borderPath); 1019 graphicsContext.strokePath(borderPath);
1000 return; 1020 return;
1001 } 1021 }
1002 case BorderStyleDouble: { 1022 case BorderStyleDouble: {
1003 // Draw inner border line 1023 // Draw inner border line
1004 { 1024 {
1005 GraphicsContextStateSaver stateSaver(graphicsContext); 1025 GraphicsContextStateSaver stateSaver(graphicsContext);
1006 const LayoutRectOutsets innerInsets = 1026 const LayoutRectOutsets innerInsets =
1007 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeInner); 1027 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeInner);
1008 FloatRoundedRect innerClip = m_style.getRoundedInnerBorderFor( 1028 FloatRoundedRect innerClip = m_style.getRoundedInnerBorderFor(
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1102 BoxSide side, 1122 BoxSide side,
1103 MiterType firstMiter, 1123 MiterType firstMiter,
1104 MiterType secondMiter) const { 1124 MiterType secondMiter) const {
1105 ASSERT(firstMiter != NoMiter || secondMiter != NoMiter); 1125 ASSERT(firstMiter != NoMiter || secondMiter != NoMiter);
1106 1126
1107 FloatPoint quad[4]; 1127 FloatPoint quad[4];
1108 1128
1109 const LayoutRect outerRect(m_outer.rect()); 1129 const LayoutRect outerRect(m_outer.rect());
1110 const LayoutRect innerRect(m_inner.rect()); 1130 const LayoutRect innerRect(m_inner.rect());
1111 1131
1112 // For each side, create a quad that encompasses all parts of that side that m ay draw, 1132 // For each side, create a quad that encompasses all parts of that side that
1113 // including areas inside the innerBorder. 1133 // may draw, including areas inside the innerBorder.
1114 // 1134 //
1115 // 0----------------3 1135 // 0----------------3
1116 // 0 \ / 0 1136 // 0 \ / 0
1117 // |\ 1----------- 2 /| 1137 // |\ 1----------- 2 /|
1118 // | 1 1 | 1138 // | 1 1 |
1119 // | | | | 1139 // | | | |
1120 // | | | | 1140 // | | | |
1121 // | 2 2 | 1141 // | 2 2 |
1122 // |/ 1------------2 \| 1142 // |/ 1------------2 \|
1123 // 3 / \ 3 1143 // 3 / \ 3
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
1274 FloatPoint secondQuad[4]; 1294 FloatPoint secondQuad[4];
1275 secondQuad[0] = quad[0]; 1295 secondQuad[0] = quad[0];
1276 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy); 1296 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy);
1277 secondQuad[2] = quad[2]; 1297 secondQuad[2] = quad[2];
1278 secondQuad[3] = quad[3]; 1298 secondQuad[3] = quad[3];
1279 clipQuad(graphicsContext, secondQuad, secondMiter == SoftMiter); 1299 clipQuad(graphicsContext, secondQuad, secondMiter == SoftMiter);
1280 } 1300 }
1281 } 1301 }
1282 1302
1283 } // namespace blink 1303 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/paint/BlockPainter.cpp ('k') | third_party/WebKit/Source/core/paint/BoxClipper.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698