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

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

Issue 1512803004: Use refs for GraphicsContext (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@ScrollbarTheme
Patch Set: Created 5 years 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 "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"
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 LayoutRectOutsets doubleStripeInsets(const BorderEdge edges[], BorderEdge::Doubl eBorderStripe stripe) 244 LayoutRectOutsets doubleStripeInsets(const BorderEdge edges[], BorderEdge::Doubl eBorderStripe stripe)
245 { 245 {
246 // Insets are representes as negative outsets. 246 // Insets are representes as negative outsets.
247 return LayoutRectOutsets( 247 return LayoutRectOutsets(
248 -edges[BSTop].getDoubleBorderStripeWidth(stripe), 248 -edges[BSTop].getDoubleBorderStripeWidth(stripe),
249 -edges[BSRight].getDoubleBorderStripeWidth(stripe), 249 -edges[BSRight].getDoubleBorderStripeWidth(stripe),
250 -edges[BSBottom].getDoubleBorderStripeWidth(stripe), 250 -edges[BSBottom].getDoubleBorderStripeWidth(stripe),
251 -edges[BSLeft].getDoubleBorderStripeWidth(stripe)); 251 -edges[BSLeft].getDoubleBorderStripeWidth(stripe));
252 } 252 }
253 253
254 void drawSolidBorderRect(GraphicsContext* context, const FloatRect& borderRect, 254 void drawSolidBorderRect(GraphicsContext& context, const FloatRect& borderRect,
255 float borderWidth, const Color& color) 255 float borderWidth, const Color& color)
256 { 256 {
257 FloatRect strokeRect(borderRect); 257 FloatRect strokeRect(borderRect);
258 strokeRect.inflate(-borderWidth / 2); 258 strokeRect.inflate(-borderWidth / 2);
259 259
260 bool wasAntialias = context->shouldAntialias(); 260 bool wasAntialias = context.shouldAntialias();
261 if (!wasAntialias) 261 if (!wasAntialias)
262 context->setShouldAntialias(true); 262 context.setShouldAntialias(true);
263 263
264 context->setStrokeStyle(SolidStroke); 264 context.setStrokeStyle(SolidStroke);
265 context->setStrokeColor(color); 265 context.setStrokeColor(color);
266 context->strokeRect(strokeRect, borderWidth); 266 context.strokeRect(strokeRect, borderWidth);
267 267
268 if (!wasAntialias) 268 if (!wasAntialias)
269 context->setShouldAntialias(false); 269 context.setShouldAntialias(false);
270 } 270 }
271 271
272 void drawBleedAdjustedDRRect(GraphicsContext* context, BackgroundBleedAvoidance bleedAvoidance, 272 void drawBleedAdjustedDRRect(GraphicsContext& context, BackgroundBleedAvoidance bleedAvoidance,
273 const FloatRoundedRect& outer, const FloatRoundedRect& inner, Color color) 273 const FloatRoundedRect& outer, const FloatRoundedRect& inner, Color color)
274 { 274 {
275 switch (bleedAvoidance) { 275 switch (bleedAvoidance) {
276 case BackgroundBleedClipLayer: { 276 case BackgroundBleedClipLayer: {
277 // BackgroundBleedClipLayer clips the outer rrect for the whole layer. B ased on this, 277 // BackgroundBleedClipLayer clips the outer rrect for the whole layer. B ased on this,
278 // we can avoid background bleeding by filling the *outside* of inner rr ect, all the 278 // we can avoid background bleeding by filling the *outside* of inner rr ect, all the
279 // way to the layer bounds (enclosing int rect for the clip, in device s pace). 279 // way to the layer bounds (enclosing int rect for the clip, in device s pace).
280 ASSERT(outer.isRounded()); 280 ASSERT(outer.isRounded());
281 281
282 SkPath path; 282 SkPath path;
283 path.addRRect(inner); 283 path.addRRect(inner);
284 path.setFillType(SkPath::kInverseWinding_FillType); 284 path.setFillType(SkPath::kInverseWinding_FillType);
285 285
286 SkPaint paint; 286 SkPaint paint;
287 paint.setColor(color.rgb()); 287 paint.setColor(color.rgb());
288 paint.setStyle(SkPaint::kFill_Style); 288 paint.setStyle(SkPaint::kFill_Style);
289 paint.setAntiAlias(true); 289 paint.setAntiAlias(true);
290 context->drawPath(path, paint); 290 context.drawPath(path, paint);
291 291
292 break; 292 break;
293 } 293 }
294 case BackgroundBleedClipOnly: 294 case BackgroundBleedClipOnly:
295 if (outer.isRounded()) { 295 if (outer.isRounded()) {
296 // BackgroundBleedClipOnly clips the outer rrect corners for us. 296 // BackgroundBleedClipOnly clips the outer rrect corners for us.
297 FloatRoundedRect adjustedOuter = outer; 297 FloatRoundedRect adjustedOuter = outer;
298 adjustedOuter.setRadii(FloatRoundedRect::Radii()); 298 adjustedOuter.setRadii(FloatRoundedRect::Radii());
299 context->fillDRRect(adjustedOuter, inner, color); 299 context.fillDRRect(adjustedOuter, inner, color);
300 break; 300 break;
301 } 301 }
302 // fall through 302 // fall through
303 default: 303 default:
304 context->fillDRRect(outer, inner, color); 304 context.fillDRRect(outer, inner, color);
305 break; 305 break;
306 } 306 }
307 } 307 }
308 308
309 bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance) 309 bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance)
310 { 310 {
311 return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == Backgr oundBleedClipLayer; 311 return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == Backgr oundBleedClipLayer;
312 } 312 }
313 313
314 // The LUTs below assume specific enum values. 314 // The LUTs below assume specific enum values.
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 ASSERT(!opacityGroups.isEmpty()); 432 ASSERT(!opacityGroups.isEmpty());
433 OpacityGroup& currentGroup = opacityGroups.last(); 433 OpacityGroup& currentGroup = opacityGroups.last();
434 currentGroup.sides.append(side); 434 currentGroup.sides.append(side);
435 currentGroup.edgeFlags |= edgeFlagForSide(side); 435 currentGroup.edgeFlags |= edgeFlagForSide(side);
436 } 436 }
437 437
438 ASSERT(!opacityGroups.isEmpty()); 438 ASSERT(!opacityGroups.isEmpty());
439 } 439 }
440 }; 440 };
441 441
442 void BoxBorderPainter::drawDoubleBorder(GraphicsContext* context, const LayoutRe ct& borderRect) const 442 void BoxBorderPainter::drawDoubleBorder(GraphicsContext& context, const LayoutRe ct& borderRect) const
443 { 443 {
444 ASSERT(m_isUniformColor); 444 ASSERT(m_isUniformColor);
445 ASSERT(m_isUniformStyle); 445 ASSERT(m_isUniformStyle);
446 ASSERT(firstEdge().borderStyle() == DOUBLE); 446 ASSERT(firstEdge().borderStyle() == DOUBLE);
447 ASSERT(m_visibleEdgeSet == AllBorderEdges); 447 ASSERT(m_visibleEdgeSet == AllBorderEdges);
448 448
449 const Color color = firstEdge().color; 449 const Color color = firstEdge().color;
450 450
451 // outer stripe 451 // outer stripe
452 const LayoutRectOutsets outerThirdInsets = 452 const LayoutRectOutsets outerThirdInsets =
453 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeOuter); 453 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeOuter);
454 const FloatRoundedRect outerThirdRect = m_style.getRoundedInnerBorderFor(bor derRect, 454 const FloatRoundedRect outerThirdRect = m_style.getRoundedInnerBorderFor(bor derRect,
455 outerThirdInsets, m_includeLogicalLeftEdge, m_includeLogicalRightEdge); 455 outerThirdInsets, m_includeLogicalLeftEdge, m_includeLogicalRightEdge);
456 drawBleedAdjustedDRRect(context, m_bleedAvoidance, m_outer, outerThirdRect, color); 456 drawBleedAdjustedDRRect(context, m_bleedAvoidance, m_outer, outerThirdRect, color);
457 457
458 // inner stripe 458 // inner stripe
459 const LayoutRectOutsets innerThirdInsets = 459 const LayoutRectOutsets innerThirdInsets =
460 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeInner); 460 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeInner);
461 const FloatRoundedRect innerThirdRect = m_style.getRoundedInnerBorderFor(bor derRect, 461 const FloatRoundedRect innerThirdRect = m_style.getRoundedInnerBorderFor(bor derRect,
462 innerThirdInsets, m_includeLogicalLeftEdge, m_includeLogicalRightEdge); 462 innerThirdInsets, m_includeLogicalLeftEdge, m_includeLogicalRightEdge);
463 context->fillDRRect(innerThirdRect, m_inner, color); 463 context.fillDRRect(innerThirdRect, m_inner, color);
464 } 464 }
465 465
466 bool BoxBorderPainter::paintBorderFastPath(GraphicsContext* context, const Layou tRect& borderRect) const 466 bool BoxBorderPainter::paintBorderFastPath(GraphicsContext& context, const Layou tRect& borderRect) const
467 { 467 {
468 if (!m_isUniformColor || !m_isUniformStyle || !m_inner.isRenderable()) 468 if (!m_isUniformColor || !m_isUniformStyle || !m_inner.isRenderable())
469 return false; 469 return false;
470 470
471 if (firstEdge().borderStyle() != SOLID && firstEdge().borderStyle() != DOUBL E) 471 if (firstEdge().borderStyle() != SOLID && firstEdge().borderStyle() != DOUBL E)
472 return false; 472 return false;
473 473
474 if (m_visibleEdgeSet == AllBorderEdges) { 474 if (m_visibleEdgeSet == AllBorderEdges) {
475 if (firstEdge().borderStyle() == SOLID) { 475 if (firstEdge().borderStyle() == SOLID) {
476 if (m_isUniformWidth && !m_outer.isRounded()) { 476 if (m_isUniformWidth && !m_outer.isRounded()) {
(...skipping 19 matching lines...) Expand all
496 // solid, rectangular border => one drawPath() 496 // solid, rectangular border => one drawPath()
497 Path path; 497 Path path;
498 path.setWindRule(RULE_NONZERO); 498 path.setWindRule(RULE_NONZERO);
499 499
500 for (int i = BSTop; i <= BSLeft; ++i) { 500 for (int i = BSTop; i <= BSLeft; ++i) {
501 const BorderEdge& currEdge = m_edges[i]; 501 const BorderEdge& currEdge = m_edges[i];
502 if (currEdge.shouldRender()) 502 if (currEdge.shouldRender())
503 path.addRect(calculateSideRect(m_outer, currEdge, i)); 503 path.addRect(calculateSideRect(m_outer, currEdge, i));
504 } 504 }
505 505
506 context->setFillColor(firstEdge().color); 506 context.setFillColor(firstEdge().color);
507 context->fillPath(path); 507 context.fillPath(path);
508 return true; 508 return true;
509 } 509 }
510 510
511 return false; 511 return false;
512 } 512 }
513 513
514 BoxBorderPainter::BoxBorderPainter(const LayoutRect& borderRect, const ComputedS tyle& style, 514 BoxBorderPainter::BoxBorderPainter(const LayoutRect& borderRect, const ComputedS tyle& style,
515 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, 515 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge,
516 bool includeLogicalRightEdge) 516 bool includeLogicalRightEdge)
517 : m_style(style) 517 : m_style(style)
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 m_isUniformWidth &= edge.width == m_edges[m_firstVisibleEdge].width; 593 m_isUniformWidth &= edge.width == m_edges[m_firstVisibleEdge].width;
594 m_isUniformColor &= edge.color == m_edges[m_firstVisibleEdge].color; 594 m_isUniformColor &= edge.color == m_edges[m_firstVisibleEdge].color;
595 } 595 }
596 } 596 }
597 597
598 void BoxBorderPainter::paintBorder(const PaintInfo& info, const LayoutRect& rect ) const 598 void BoxBorderPainter::paintBorder(const PaintInfo& info, const LayoutRect& rect ) const
599 { 599 {
600 if (!m_visibleEdgeCount || m_outer.rect().isEmpty()) 600 if (!m_visibleEdgeCount || m_outer.rect().isEmpty())
601 return; 601 return;
602 602
603 GraphicsContext* graphicsContext = info.context; 603 GraphicsContext& graphicsContext = info.context;
604 604
605 if (paintBorderFastPath(graphicsContext, rect)) 605 if (paintBorderFastPath(graphicsContext, rect))
606 return; 606 return;
607 607
608 bool clipToOuterBorder = m_outer.isRounded(); 608 bool clipToOuterBorder = m_outer.isRounded();
609 GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder); 609 GraphicsContextStateSaver stateSaver(graphicsContext, clipToOuterBorder);
610 if (clipToOuterBorder) { 610 if (clipToOuterBorder) {
611 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already applied. 611 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already applied.
612 if (!bleedAvoidanceIsClipping(m_bleedAvoidance)) 612 if (!bleedAvoidanceIsClipping(m_bleedAvoidance))
613 graphicsContext->clipRoundedRect(m_outer); 613 graphicsContext.clipRoundedRect(m_outer);
614 614
615 if (m_inner.isRenderable() && !m_inner.isEmpty()) 615 if (m_inner.isRenderable() && !m_inner.isEmpty())
616 graphicsContext->clipOutRoundedRect(m_inner); 616 graphicsContext.clipOutRoundedRect(m_inner);
617 } 617 }
618 618
619 const ComplexBorderInfo borderInfo(*this, true); 619 const ComplexBorderInfo borderInfo(*this, true);
620 paintOpacityGroup(graphicsContext, borderInfo, 0, 1); 620 paintOpacityGroup(graphicsContext, borderInfo, 0, 1);
621 } 621 }
622 622
623 // In order to maximize the use of overdraw as a corner seam avoidance technique , we draw 623 // In order to maximize the use of overdraw as a corner seam avoidance technique , we draw
624 // translucent border sides using the following algorithm: 624 // translucent border sides using the following algorithm:
625 // 625 //
626 // 1) cluster sides sharing the same opacity into "opacity groups" [ComplexBor derInfo] 626 // 1) cluster sides sharing the same opacity into "opacity groups" [ComplexBor derInfo]
(...skipping 28 matching lines...) Expand all
655 // beginLayer(0.5) // layer for group 2 (effective opacity: 0.5 * 0.5 == 0.25) 655 // beginLayer(0.5) // layer for group 2 (effective opacity: 0.5 * 0.5 == 0.25)
656 // paintSides(right, left) // paint group 2 656 // paintSides(right, left) // paint group 2
657 // endLayer 657 // endLayer
658 // paintSides(bottom) // paint group 1 658 // paintSides(bottom) // paint group 1
659 // endLayer 659 // endLayer
660 // paintSides(top) // paint group 0 660 // paintSides(top) // paint group 0
661 // 661 //
662 // Note that we're always drawing using opaque paints on top of less-opaque cont ent - hence 662 // Note that we're always drawing using opaque paints on top of less-opaque cont ent - hence
663 // we can use overdraw to mask portions of the previous sides. 663 // we can use overdraw to mask portions of the previous sides.
664 // 664 //
665 BorderEdgeFlags BoxBorderPainter::paintOpacityGroup(GraphicsContext* context, 665 BorderEdgeFlags BoxBorderPainter::paintOpacityGroup(GraphicsContext& context,
666 const ComplexBorderInfo& borderInfo, unsigned index, float effectiveOpacity) const 666 const ComplexBorderInfo& borderInfo, unsigned index, float effectiveOpacity) const
667 { 667 {
668 ASSERT(effectiveOpacity > 0 && effectiveOpacity <= 1); 668 ASSERT(effectiveOpacity > 0 && effectiveOpacity <= 1);
669 669
670 const size_t opacityGroupCount = borderInfo.opacityGroups.size(); 670 const size_t opacityGroupCount = borderInfo.opacityGroups.size();
671 671
672 // For overdraw logic purposes, treat missing/transparent edges as completed . 672 // For overdraw logic purposes, treat missing/transparent edges as completed .
673 if (index >= opacityGroupCount) 673 if (index >= opacityGroupCount)
674 return ~m_visibleEdgeSet; 674 return ~m_visibleEdgeSet;
675 675
676 // Groups are sorted in increasing opacity order, but we need to create laye rs in 676 // Groups are sorted in increasing opacity order, but we need to create laye rs in
677 // decreasing opacity order - hence the reverse iteration. 677 // decreasing opacity order - hence the reverse iteration.
678 const OpacityGroup& group = borderInfo.opacityGroups[opacityGroupCount - ind ex - 1]; 678 const OpacityGroup& group = borderInfo.opacityGroups[opacityGroupCount - ind ex - 1];
679 679
680 // Adjust this group's paint opacity to account for ancestor transparency la yers 680 // Adjust this group's paint opacity to account for ancestor transparency la yers
681 // (needed in case we avoid creating a layer below). 681 // (needed in case we avoid creating a layer below).
682 unsigned paintAlpha = group.alpha / effectiveOpacity; 682 unsigned paintAlpha = group.alpha / effectiveOpacity;
683 ASSERT(paintAlpha <= 255); 683 ASSERT(paintAlpha <= 255);
684 684
685 // For the last (bottom) group, we can skip the layer even in the presence o f opacity iff 685 // For the last (bottom) group, we can skip the layer even in the presence o f opacity iff
686 // it contains no adjecent edges (no in-group overdraw possibility). 686 // it contains no adjecent edges (no in-group overdraw possibility).
687 bool needsLayer = group.alpha != 255 687 bool needsLayer = group.alpha != 255
688 && (includesAdjacentEdges(group.edgeFlags) || (index + 1 < borderInfo.op acityGroups.size())); 688 && (includesAdjacentEdges(group.edgeFlags) || (index + 1 < borderInfo.op acityGroups.size()));
689 689
690 if (needsLayer) { 690 if (needsLayer) {
691 const float groupOpacity = static_cast<float>(group.alpha) / 255; 691 const float groupOpacity = static_cast<float>(group.alpha) / 255;
692 ASSERT(groupOpacity < effectiveOpacity); 692 ASSERT(groupOpacity < effectiveOpacity);
693 693
694 context->beginLayer(groupOpacity / effectiveOpacity); 694 context.beginLayer(groupOpacity / effectiveOpacity);
695 effectiveOpacity = groupOpacity; 695 effectiveOpacity = groupOpacity;
696 696
697 // Group opacity is applied via a layer => we draw the members using opa que paint. 697 // Group opacity is applied via a layer => we draw the members using opa que paint.
698 paintAlpha = 255; 698 paintAlpha = 255;
699 } 699 }
700 700
701 // Recursion may seem unpalatable here, but 701 // Recursion may seem unpalatable here, but
702 // a) it has an upper bound of 4 702 // a) it has an upper bound of 4
703 // b) only triggers at all when mixing border sides with different opaciti es 703 // b) only triggers at all when mixing border sides with different opaciti es
704 // c) it allows us to express the layer nesting algorithm more naturally 704 // c) it allows us to express the layer nesting algorithm more naturally
705 BorderEdgeFlags completedEdges = paintOpacityGroup(context, borderInfo, inde x + 1, effectiveOpacity); 705 BorderEdgeFlags completedEdges = paintOpacityGroup(context, borderInfo, inde x + 1, effectiveOpacity);
706 706
707 // Paint the actual group edges with an alpha adjusted to account for ancens tor layers opacity. 707 // Paint the actual group edges with an alpha adjusted to account for ancens tor layers opacity.
708 for (BoxSide side : group.sides) { 708 for (BoxSide side : group.sides) {
709 paintSide(context, borderInfo, side, paintAlpha, completedEdges); 709 paintSide(context, borderInfo, side, paintAlpha, completedEdges);
710 completedEdges |= edgeFlagForSide(side); 710 completedEdges |= edgeFlagForSide(side);
711 } 711 }
712 712
713 if (needsLayer) 713 if (needsLayer)
714 context->endLayer(); 714 context.endLayer();
715 715
716 return completedEdges; 716 return completedEdges;
717 } 717 }
718 718
719 void BoxBorderPainter::paintSide(GraphicsContext* context, const ComplexBorderIn fo& borderInfo, 719 void BoxBorderPainter::paintSide(GraphicsContext& context, const ComplexBorderIn fo& borderInfo,
720 BoxSide side, unsigned alpha, BorderEdgeFlags completedEdges) const 720 BoxSide side, unsigned alpha, BorderEdgeFlags completedEdges) const
721 { 721 {
722 const BorderEdge& edge = m_edges[side]; 722 const BorderEdge& edge = m_edges[side];
723 ASSERT(edge.shouldRender()); 723 ASSERT(edge.shouldRender());
724 const Color color(edge.color.red(), edge.color.green(), edge.color.blue(), a lpha); 724 const Color color(edge.color.red(), edge.color.green(), edge.color.blue(), a lpha);
725 725
726 FloatRect sideRect = m_outer.rect(); 726 FloatRect sideRect = m_outer.rect();
727 const Path* path = nullptr; 727 const Path* path = nullptr;
728 728
729 // TODO(fmalita): find a way to consolidate these without sacrificing readab ility. 729 // TODO(fmalita): find a way to consolidate these without sacrificing readab ility.
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 ? miter1 == HardMiter || miter2 == HardMiter 815 ? miter1 == HardMiter || miter2 == HardMiter
816 : miter1 == SoftMiter || miter2 == SoftMiter; 816 : miter1 == SoftMiter || miter2 == SoftMiter;
817 817
818 // Some styles require clipping for any type of miter. 818 // Some styles require clipping for any type of miter.
819 shouldClip = shouldClip 819 shouldClip = shouldClip
820 || ((miter1 != NoMiter || miter2 != NoMiter) && styleRequiresClipPolygon (style)); 820 || ((miter1 != NoMiter || miter2 != NoMiter) && styleRequiresClipPolygon (style));
821 821
822 return shouldClip; 822 return shouldClip;
823 } 823 }
824 824
825 void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext, 825 void BoxBorderPainter::paintOneBorderSide(GraphicsContext& graphicsContext,
826 const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adja centSide2, 826 const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adja centSide2,
827 const Path* path, bool antialias, Color color, BorderEdgeFlags completedEdge s) const 827 const Path* path, bool antialias, Color color, BorderEdgeFlags completedEdge s) const
828 { 828 {
829 const BorderEdge& edgeToRender = m_edges[side]; 829 const BorderEdge& edgeToRender = m_edges[side];
830 ASSERT(edgeToRender.width); 830 ASSERT(edgeToRender.width);
831 const BorderEdge& adjacentEdge1 = m_edges[adjacentSide1]; 831 const BorderEdge& adjacentEdge1 = m_edges[adjacentSide1];
832 const BorderEdge& adjacentEdge2 = m_edges[adjacentSide2]; 832 const BorderEdge& adjacentEdge2 = m_edges[adjacentSide2];
833 833
834 if (path) { 834 if (path) {
835 MiterType miter1 = colorsMatchAtCorner(side, adjacentSide1, m_edges) ? H ardMiter : SoftMiter; 835 MiterType miter1 = colorsMatchAtCorner(side, adjacentSide1, m_edges) ? H ardMiter : SoftMiter;
836 MiterType miter2 = colorsMatchAtCorner(side, adjacentSide2, m_edges) ? H ardMiter : SoftMiter; 836 MiterType miter2 = colorsMatchAtCorner(side, adjacentSide2, m_edges) ? H ardMiter : SoftMiter;
837 837
838 GraphicsContextStateSaver stateSaver(*graphicsContext); 838 GraphicsContextStateSaver stateSaver(graphicsContext);
839 if (m_inner.isRenderable()) 839 if (m_inner.isRenderable())
840 clipBorderSidePolygon(graphicsContext, side, miter1, miter2); 840 clipBorderSidePolygon(graphicsContext, side, miter1, miter2);
841 else 841 else
842 clipBorderSideForComplexInnerPath(graphicsContext, side); 842 clipBorderSideForComplexInnerPath(graphicsContext, side);
843 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi dth), adjacentEdge2.width); 843 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi dth), adjacentEdge2.width);
844 drawBoxSideFromPath(graphicsContext, LayoutRect(m_outer.rect()), *path, edgeToRender.width, 844 drawBoxSideFromPath(graphicsContext, LayoutRect(m_outer.rect()), *path, edgeToRender.width,
845 thickness, side, color, edgeToRender.borderStyle()); 845 thickness, side, color, edgeToRender.borderStyle());
846 } else { 846 } else {
847 MiterType miter1 = computeMiter(side, adjacentSide1, completedEdges, ant ialias); 847 MiterType miter1 = computeMiter(side, adjacentSide1, completedEdges, ant ialias);
848 MiterType miter2 = computeMiter(side, adjacentSide2, completedEdges, ant ialias); 848 MiterType miter2 = computeMiter(side, adjacentSide2, completedEdges, ant ialias);
849 bool shouldClip = mitersRequireClipping(miter1, miter2, edgeToRender.bor derStyle(), antialias); 849 bool shouldClip = mitersRequireClipping(miter1, miter2, edgeToRender.bor derStyle(), antialias);
850 850
851 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip); 851 GraphicsContextStateSaver clipStateSaver(graphicsContext, shouldClip);
852 if (shouldClip) { 852 if (shouldClip) {
853 clipBorderSidePolygon(graphicsContext, side, miter1, miter2); 853 clipBorderSidePolygon(graphicsContext, side, miter1, miter2);
854 854
855 // Miters are applied via clipping, no need to draw them. 855 // Miters are applied via clipping, no need to draw them.
856 miter1 = miter2 = NoMiter; 856 miter1 = miter2 = NoMiter;
857 } 857 }
858 858
859 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec t.y(), 859 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec t.y(),
860 sideRect.maxX(), sideRect.maxY(), side, color, edgeToRender.borderSt yle(), 860 sideRect.maxX(), sideRect.maxY(), side, color, edgeToRender.borderSt yle(),
861 miter1 != NoMiter ? adjacentEdge1.width : 0, miter2 != NoMiter ? adj acentEdge2.width : 0, 861 miter1 != NoMiter ? adjacentEdge1.width : 0, miter2 != NoMiter ? adj acentEdge2.width : 0,
862 antialias); 862 antialias);
863 } 863 }
864 } 864 }
865 865
866 void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext, 866 void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext& graphicsContext,
867 const LayoutRect& borderRect, const Path& borderPath, float thickness, float drawThickness, 867 const LayoutRect& borderRect, const Path& borderPath, float thickness, float drawThickness,
868 BoxSide side, Color color, EBorderStyle borderStyle) const 868 BoxSide side, Color color, EBorderStyle borderStyle) const
869 { 869 {
870 if (thickness <= 0) 870 if (thickness <= 0)
871 return; 871 return;
872 872
873 if (borderStyle == DOUBLE && thickness < 3) 873 if (borderStyle == DOUBLE && thickness < 3)
874 borderStyle = SOLID; 874 borderStyle = SOLID;
875 875
876 switch (borderStyle) { 876 switch (borderStyle) {
877 case BNONE: 877 case BNONE:
878 case BHIDDEN: 878 case BHIDDEN:
879 return; 879 return;
880 case DOTTED: 880 case DOTTED:
881 case DASHED: { 881 case DASHED: {
882 graphicsContext->setStrokeColor(color); 882 graphicsContext.setStrokeColor(color);
883 883
884 // The stroke is doubled here because the provided path is the 884 // The stroke is doubled here because the provided path is the
885 // outside edge of the border so half the stroke is clipped off. 885 // outside edge of the border so half the stroke is clipped off.
886 // The extra multiplier is so that the clipping mask can antialias 886 // The extra multiplier is so that the clipping mask can antialias
887 // the edges to prevent jaggies. 887 // the edges to prevent jaggies.
888 graphicsContext->setStrokeThickness(drawThickness * 2 * 1.1f); 888 graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f);
889 graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : D ottedStroke); 889 graphicsContext.setStrokeStyle(borderStyle == DASHED ? DashedStroke : Do ttedStroke);
890 890
891 // If the number of dashes that fit in the path is odd and non-integral then we 891 // If the number of dashes that fit in the path is odd and non-integral then we
892 // will have an awkwardly-sized dash at the end of the path. To try to a void that 892 // will have an awkwardly-sized dash at the end of the path. To try to a void that
893 // here, we simply make the whitespace dashes ever so slightly bigger. 893 // here, we simply make the whitespace dashes ever so slightly bigger.
894 // FIXME: This could be even better if we tried to manipulate the dash o ffset 894 // FIXME: This could be even better if we tried to manipulate the dash o ffset
895 // and possibly the gapLength to get the corners dash-symmetrical. 895 // and possibly the gapLength to get the corners dash-symmetrical.
896 float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f); 896 float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f);
897 float gapLength = dashLength; 897 float gapLength = dashLength;
898 float numberOfDashes = borderPath.length() / dashLength; 898 float numberOfDashes = borderPath.length() / dashLength;
899 // Don't try to show dashes if we have less than 2 dashes + 2 gaps. 899 // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
900 // FIXME: should do this test per side. 900 // FIXME: should do this test per side.
901 if (numberOfDashes >= 4) { 901 if (numberOfDashes >= 4) {
902 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2); 902 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
903 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes ); 903 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes );
904 if (!evenNumberOfFullDashes && !integralNumberOfDashes) { 904 if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
905 float numberOfGaps = numberOfDashes / 2; 905 float numberOfGaps = numberOfDashes / 2;
906 gapLength += (dashLength / numberOfGaps); 906 gapLength += (dashLength / numberOfGaps);
907 } 907 }
908 908
909 DashArray lineDash; 909 DashArray lineDash;
910 lineDash.append(dashLength); 910 lineDash.append(dashLength);
911 lineDash.append(gapLength); 911 lineDash.append(gapLength);
912 graphicsContext->setLineDash(lineDash, dashLength); 912 graphicsContext.setLineDash(lineDash, dashLength);
913 } 913 }
914 914
915 // FIXME: stroking the border path causes issues with tight corners: 915 // FIXME: stroking the border path causes issues with tight corners:
916 // https://bugs.webkit.org/show_bug.cgi?id=58711 916 // https://bugs.webkit.org/show_bug.cgi?id=58711
917 // Also, to get the best appearance we should stroke a path between the two borders. 917 // Also, to get the best appearance we should stroke a path between the two borders.
918 graphicsContext->strokePath(borderPath); 918 graphicsContext.strokePath(borderPath);
919 return; 919 return;
920 } 920 }
921 case DOUBLE: { 921 case DOUBLE: {
922 // Draw inner border line 922 // Draw inner border line
923 { 923 {
924 GraphicsContextStateSaver stateSaver(*graphicsContext); 924 GraphicsContextStateSaver stateSaver(graphicsContext);
925 const LayoutRectOutsets innerInsets = doubleStripeInsets(m_edges, Bo rderEdge::DoubleBorderStripeInner); 925 const LayoutRectOutsets innerInsets = doubleStripeInsets(m_edges, Bo rderEdge::DoubleBorderStripeInner);
926 FloatRoundedRect innerClip = m_style.getRoundedInnerBorderFor(border Rect, innerInsets, 926 FloatRoundedRect innerClip = m_style.getRoundedInnerBorderFor(border Rect, innerInsets,
927 m_includeLogicalLeftEdge, m_includeLogicalRightEdge); 927 m_includeLogicalLeftEdge, m_includeLogicalRightEdge);
928 928
929 graphicsContext->clipRoundedRect(innerClip); 929 graphicsContext.clipRoundedRect(innerClip);
930 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickne ss, drawThickness, 930 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickne ss, drawThickness,
931 side, color, SOLID); 931 side, color, SOLID);
932 } 932 }
933 933
934 // Draw outer border line 934 // Draw outer border line
935 { 935 {
936 GraphicsContextStateSaver stateSaver(*graphicsContext); 936 GraphicsContextStateSaver stateSaver(graphicsContext);
937 LayoutRect outerRect = borderRect; 937 LayoutRect outerRect = borderRect;
938 LayoutRectOutsets outerInsets = doubleStripeInsets(m_edges, BorderEd ge::DoubleBorderStripeOuter); 938 LayoutRectOutsets outerInsets = doubleStripeInsets(m_edges, BorderEd ge::DoubleBorderStripeOuter);
939 939
940 if (bleedAvoidanceIsClipping(m_bleedAvoidance)) { 940 if (bleedAvoidanceIsClipping(m_bleedAvoidance)) {
941 outerRect.inflate(1); 941 outerRect.inflate(1);
942 outerInsets.setTop(outerInsets.top() - 1); 942 outerInsets.setTop(outerInsets.top() - 1);
943 outerInsets.setRight(outerInsets.right() - 1); 943 outerInsets.setRight(outerInsets.right() - 1);
944 outerInsets.setBottom(outerInsets.bottom() - 1); 944 outerInsets.setBottom(outerInsets.bottom() - 1);
945 outerInsets.setLeft(outerInsets.left() - 1); 945 outerInsets.setLeft(outerInsets.left() - 1);
946 } 946 }
947 947
948 FloatRoundedRect outerClip = m_style.getRoundedInnerBorderFor(outerR ect, outerInsets, 948 FloatRoundedRect outerClip = m_style.getRoundedInnerBorderFor(outerR ect, outerInsets,
949 m_includeLogicalLeftEdge, m_includeLogicalRightEdge); 949 m_includeLogicalLeftEdge, m_includeLogicalRightEdge);
950 graphicsContext->clipOutRoundedRect(outerClip); 950 graphicsContext.clipOutRoundedRect(outerClip);
951 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickne ss, drawThickness, 951 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickne ss, drawThickness,
952 side, color, SOLID); 952 side, color, SOLID);
953 } 953 }
954 return; 954 return;
955 } 955 }
956 case RIDGE: 956 case RIDGE:
957 case GROOVE: 957 case GROOVE:
958 { 958 {
959 EBorderStyle s1; 959 EBorderStyle s1;
960 EBorderStyle s2; 960 EBorderStyle s2;
961 if (borderStyle == GROOVE) { 961 if (borderStyle == GROOVE) {
962 s1 = INSET; 962 s1 = INSET;
963 s2 = OUTSET; 963 s2 = OUTSET;
964 } else { 964 } else {
965 s1 = OUTSET; 965 s1 = OUTSET;
966 s2 = INSET; 966 s2 = INSET;
967 } 967 }
968 968
969 // Paint full border 969 // Paint full border
970 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness, 970 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness,
971 side, color, s1); 971 side, color, s1);
972 972
973 // Paint inner only 973 // Paint inner only
974 GraphicsContextStateSaver stateSaver(*graphicsContext); 974 GraphicsContextStateSaver stateSaver(graphicsContext);
975 LayoutUnit topWidth = m_edges[BSTop].usedWidth() / 2; 975 LayoutUnit topWidth = m_edges[BSTop].usedWidth() / 2;
976 LayoutUnit bottomWidth = m_edges[BSBottom].usedWidth() / 2; 976 LayoutUnit bottomWidth = m_edges[BSBottom].usedWidth() / 2;
977 LayoutUnit leftWidth = m_edges[BSLeft].usedWidth() / 2; 977 LayoutUnit leftWidth = m_edges[BSLeft].usedWidth() / 2;
978 LayoutUnit rightWidth = m_edges[BSRight].usedWidth() / 2; 978 LayoutUnit rightWidth = m_edges[BSRight].usedWidth() / 2;
979 979
980 FloatRoundedRect clipRect = m_style.getRoundedInnerBorderFor(borderRect, 980 FloatRoundedRect clipRect = m_style.getRoundedInnerBorderFor(borderRect,
981 LayoutRectOutsets(-topWidth, -rightWidth, -bottomWidth, -leftWidth), 981 LayoutRectOutsets(-topWidth, -rightWidth, -bottomWidth, -leftWidth),
982 m_includeLogicalLeftEdge, m_includeLogicalRightEdge); 982 m_includeLogicalLeftEdge, m_includeLogicalRightEdge);
983 983
984 graphicsContext->clipRoundedRect(clipRect); 984 graphicsContext.clipRoundedRect(clipRect);
985 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness, 985 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness, drawThickness,
986 side, color, s2); 986 side, color, s2);
987 return; 987 return;
988 } 988 }
989 case INSET: 989 case INSET:
990 if (side == BSTop || side == BSLeft) 990 if (side == BSTop || side == BSLeft)
991 color = color.dark(); 991 color = color.dark();
992 break; 992 break;
993 case OUTSET: 993 case OUTSET:
994 if (side == BSBottom || side == BSRight) 994 if (side == BSBottom || side == BSRight)
995 color = color.dark(); 995 color = color.dark();
996 break; 996 break;
997 default: 997 default:
998 break; 998 break;
999 } 999 }
1000 1000
1001 graphicsContext->setStrokeStyle(NoStroke); 1001 graphicsContext.setStrokeStyle(NoStroke);
1002 graphicsContext->setFillColor(color); 1002 graphicsContext.setFillColor(color);
1003 graphicsContext->drawRect(pixelSnappedIntRect(borderRect)); 1003 graphicsContext.drawRect(pixelSnappedIntRect(borderRect));
1004 } 1004 }
1005 1005
1006 void BoxBorderPainter::clipBorderSideForComplexInnerPath(GraphicsContext* graphi csContext, 1006 void BoxBorderPainter::clipBorderSideForComplexInnerPath(GraphicsContext& graphi csContext,
1007 BoxSide side) const 1007 BoxSide side) const
1008 { 1008 {
1009 graphicsContext->clip(calculateSideRectIncludingInner(m_outer, m_edges, side )); 1009 graphicsContext.clip(calculateSideRectIncludingInner(m_outer, m_edges, side) );
1010 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(m_inner, s ide); 1010 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(m_inner, s ide);
1011 if (!adjustedInnerRect.isEmpty()) 1011 if (!adjustedInnerRect.isEmpty())
1012 graphicsContext->clipOutRoundedRect(adjustedInnerRect); 1012 graphicsContext.clipOutRoundedRect(adjustedInnerRect);
1013 } 1013 }
1014 1014
1015 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext* graphicsContext, B oxSide side, 1015 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext& graphicsContext, B oxSide side,
1016 MiterType firstMiter, MiterType secondMiter) const 1016 MiterType firstMiter, MiterType secondMiter) const
1017 { 1017 {
1018 ASSERT(firstMiter != NoMiter || secondMiter != NoMiter); 1018 ASSERT(firstMiter != NoMiter || secondMiter != NoMiter);
1019 1019
1020 FloatPoint quad[4]; 1020 FloatPoint quad[4];
1021 1021
1022 const LayoutRect outerRect(m_outer.rect()); 1022 const LayoutRect outerRect(m_outer.rect());
1023 const LayoutRect innerRect(m_inner.rect()); 1023 const LayoutRect innerRect(m_inner.rect());
1024 1024
1025 // For each side, create a quad that encompasses all parts of that side that may draw, 1025 // For each side, create a quad that encompasses all parts of that side that may draw,
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1148 quad[2].y()), 1148 quad[2].y()),
1149 FloatPoint( 1149 FloatPoint(
1150 quad[2].x(), 1150 quad[2].x(),
1151 quad[2].y() - m_inner.radii().bottomRight().height()), 1151 quad[2].y() - m_inner.radii().bottomRight().height()),
1152 quad[2]); 1152 quad[2]);
1153 } 1153 }
1154 break; 1154 break;
1155 } 1155 }
1156 1156
1157 if (firstMiter == secondMiter) { 1157 if (firstMiter == secondMiter) {
1158 graphicsContext->clipPolygon(4, quad, firstMiter == SoftMiter); 1158 graphicsContext.clipPolygon(4, quad, firstMiter == SoftMiter);
1159 return; 1159 return;
1160 } 1160 }
1161 1161
1162 // If antialiasing settings for the first edge and second edge is different, 1162 // If antialiasing settings for the first edge and second edge is different,
1163 // they have to be addressed separately. We do this by breaking the quad int o 1163 // they have to be addressed separately. We do this by breaking the quad int o
1164 // two parallelograms, made by moving quad[1] and quad[2]. 1164 // two parallelograms, made by moving quad[1] and quad[2].
1165 float ax = quad[1].x() - quad[0].x(); 1165 float ax = quad[1].x() - quad[0].x();
1166 float ay = quad[1].y() - quad[0].y(); 1166 float ay = quad[1].y() - quad[0].y();
1167 float bx = quad[2].x() - quad[1].x(); 1167 float bx = quad[2].x() - quad[1].x();
1168 float by = quad[2].y() - quad[1].y(); 1168 float by = quad[2].y() - quad[1].y();
(...skipping 12 matching lines...) Expand all
1181 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill; 1181 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill;
1182 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill; 1182 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill;
1183 } 1183 }
1184 1184
1185 if (firstMiter != NoMiter) { 1185 if (firstMiter != NoMiter) {
1186 FloatPoint firstQuad[4]; 1186 FloatPoint firstQuad[4];
1187 firstQuad[0] = quad[0]; 1187 firstQuad[0] = quad[0];
1188 firstQuad[1] = quad[1]; 1188 firstQuad[1] = quad[1];
1189 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay); 1189 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay);
1190 firstQuad[3] = quad[3]; 1190 firstQuad[3] = quad[3];
1191 graphicsContext->clipPolygon(4, firstQuad, firstMiter == SoftMiter); 1191 graphicsContext.clipPolygon(4, firstQuad, firstMiter == SoftMiter);
1192 } 1192 }
1193 1193
1194 if (secondMiter != NoMiter) { 1194 if (secondMiter != NoMiter) {
1195 FloatPoint secondQuad[4]; 1195 FloatPoint secondQuad[4];
1196 secondQuad[0] = quad[0]; 1196 secondQuad[0] = quad[0];
1197 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy) ; 1197 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy) ;
1198 secondQuad[2] = quad[2]; 1198 secondQuad[2] = quad[2];
1199 secondQuad[3] = quad[3]; 1199 secondQuad[3] = quad[3];
1200 graphicsContext->clipPolygon(4, secondQuad, secondMiter == SoftMiter); 1200 graphicsContext.clipPolygon(4, secondQuad, secondMiter == SoftMiter);
1201 } 1201 }
1202 } 1202 }
1203 1203
1204 } // namespace blink 1204 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/paint/BoxBorderPainter.h ('k') | third_party/WebKit/Source/core/paint/BoxClipper.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698