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

Side by Side Diff: Source/core/rendering/RenderBoxModelObject.cpp

Issue 564973002: Move a bunch more painting code out of RenderBoxModelObject and into BoxPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Merged, made more things static. Created 6 years, 3 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 | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * Copyright (C) 2010 Google Inc. All rights reserved. 7 * Copyright (C) 2010 Google Inc. All rights reserved.
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 } 304 }
305 305
306 LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const 306 LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const
307 { 307 {
308 LayoutUnit w = 0; 308 LayoutUnit w = 0;
309 if (padding.isPercent()) 309 if (padding.isPercent())
310 w = containingBlockLogicalWidthForContent(); 310 w = containingBlockLogicalWidthForContent();
311 return minimumValueForLength(padding, w); 311 return minimumValueForLength(padding, w);
312 } 312 }
313 313
314 // FIXME: See crbug.com/382491. The use of getCTM in this context is incorrect b ecause the matrix returned does not
315 // include scales applied at raster time, such as the device zoom.
316 static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRec t& rect)
317 {
318 LayoutRect shrunkRect = rect;
319 AffineTransform transform = context->getCTM();
320 shrunkRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale())));
321 shrunkRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale())));
322 return shrunkRect;
323 }
324
325 LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(Graphi csContext* context, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoida nce) const
326 {
327 // We shrink the rectangle by one pixel on each side to make it fully overla p the anti-aliased background border
328 return (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? shrinkRectB yOnePixel(context, rect) : rect;
329 }
330
331 static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRat io) 314 static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRat io)
332 { 315 {
333 return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height()); 316 return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height());
334 } 317 }
335 318
336 static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRat io) 319 static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRat io)
337 { 320 {
338 return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width()); 321 return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width());
339 } 322 }
340 323
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that 394 // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that
412 // establishes the coordinate system for the 'background-position' property. 395 // establishes the coordinate system for the 'background-position' property.
413 if (!intrinsicRatio.isEmpty()) 396 if (!intrinsicRatio.isEmpty())
414 return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio) ; 397 return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio) ;
415 398
416 // If the image has no intrinsic ratio either, then the dimensions must be a ssumed to be the rectangle that 399 // If the image has no intrinsic ratio either, then the dimensions must be a ssumed to be the rectangle that
417 // establishes the coordinate system for the 'background-position' property. 400 // establishes the coordinate system for the 'background-position' property.
418 return positioningAreaSize; 401 return positioningAreaSize;
419 } 402 }
420 403
421 static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, L ayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent)
422 {
423 if (borderSlice.isNumber())
424 return borderSlice.number() * borderSide;
425 if (borderSlice.length().isAuto())
426 return imageSide;
427 return valueForLength(borderSlice.length(), boxExtent);
428 }
429
430 bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext, const LayoutRect& rect, const RenderStyle* style,
431 const NinePieceImage& ninePieceIm age, CompositeOperator op)
432 {
433 StyleImage* styleImage = ninePieceImage.image();
434 if (!styleImage)
435 return false;
436
437 if (!styleImage->isLoaded())
438 return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
439
440 if (!styleImage->canRender(*this, style->effectiveZoom()))
441 return false;
442
443 // FIXME: border-image is broken with full page zooming when tiling has to h appen, since the tiling function
444 // doesn't have any understanding of the zoom that is in effect on the tile.
445 LayoutRect rectWithOutsets = rect;
446 rectWithOutsets.expand(style->imageOutsets(ninePieceImage));
447 IntRect borderImageRect = pixelSnappedIntRect(rectWithOutsets);
448
449 IntSize imageSize = calculateImageIntrinsicDimensions(styleImage, borderImag eRect.size(), DoNotScaleByEffectiveZoom);
450
451 // If both values are ‘auto’ then the intrinsic width and/or height of the i mage should be used, if any.
452 styleImage->setContainerSizeForRenderer(this, imageSize, style->effectiveZoo m());
453
454 int imageWidth = imageSize.width();
455 int imageHeight = imageSize.height();
456
457 float imageScaleFactor = styleImage->imageScaleFactor();
458 int topSlice = std::min<int>(imageHeight, valueForLength(ninePieceImage.imag eSlices().top(), imageHeight)) * imageScaleFactor;
459 int rightSlice = std::min<int>(imageWidth, valueForLength(ninePieceImage.ima geSlices().right(), imageWidth)) * imageScaleFactor;
460 int bottomSlice = std::min<int>(imageHeight, valueForLength(ninePieceImage.i mageSlices().bottom(), imageHeight)) * imageScaleFactor;
461 int leftSlice = std::min<int>(imageWidth, valueForLength(ninePieceImage.imag eSlices().left(), imageWidth)) * imageScaleFactor;
462
463 ENinePieceImageRule hRule = ninePieceImage.horizontalRule();
464 ENinePieceImageRule vRule = ninePieceImage.verticalRule();
465
466 int topWidth = computeBorderImageSide(ninePieceImage.borderSlices().top(), s tyle->borderTopWidth(), topSlice, borderImageRect.height());
467 int rightWidth = computeBorderImageSide(ninePieceImage.borderSlices().right( ), style->borderRightWidth(), rightSlice, borderImageRect.width());
468 int bottomWidth = computeBorderImageSide(ninePieceImage.borderSlices().botto m(), style->borderBottomWidth(), bottomSlice, borderImageRect.height());
469 int leftWidth = computeBorderImageSide(ninePieceImage.borderSlices().left(), style->borderLeftWidth(), leftSlice, borderImageRect.width());
470
471 // Reduce the widths if they're too large.
472 // The spec says: Given Lwidth as the width of the border image area, Lheigh t as its height, and Wside as the border image width
473 // offset for the side, let f = min(Lwidth/(Wleft+Wright), Lheight/(Wtop+Wbo ttom)). If f < 1, then all W are reduced by
474 // multiplying them by f.
475 int borderSideWidth = std::max(1, leftWidth + rightWidth);
476 int borderSideHeight = std::max(1, topWidth + bottomWidth);
477 float borderSideScaleFactor = std::min((float)borderImageRect.width() / bord erSideWidth, (float)borderImageRect.height() / borderSideHeight);
478 if (borderSideScaleFactor < 1) {
479 topWidth *= borderSideScaleFactor;
480 rightWidth *= borderSideScaleFactor;
481 bottomWidth *= borderSideScaleFactor;
482 leftWidth *= borderSideScaleFactor;
483 }
484
485 bool drawLeft = leftSlice > 0 && leftWidth > 0;
486 bool drawTop = topSlice > 0 && topWidth > 0;
487 bool drawRight = rightSlice > 0 && rightWidth > 0;
488 bool drawBottom = bottomSlice > 0 && bottomWidth > 0;
489 bool drawMiddle = ninePieceImage.fill() && (imageWidth - leftSlice - rightSl ice) > 0 && (borderImageRect.width() - leftWidth - rightWidth) > 0
490 && (imageHeight - topSlice - bottomSlice) > 0 && (borderIm ageRect.height() - topWidth - bottomWidth) > 0;
491
492 RefPtr<Image> image = styleImage->image(this, imageSize);
493
494 float destinationWidth = borderImageRect.width() - leftWidth - rightWidth;
495 float destinationHeight = borderImageRect.height() - topWidth - bottomWidth;
496
497 float sourceWidth = imageWidth - leftSlice - rightSlice;
498 float sourceHeight = imageHeight - topSlice - bottomSlice;
499
500 float leftSideScale = drawLeft ? (float)leftWidth / leftSlice : 1;
501 float rightSideScale = drawRight ? (float)rightWidth / rightSlice : 1;
502 float topSideScale = drawTop ? (float)topWidth / topSlice : 1;
503 float bottomSideScale = drawBottom ? (float)bottomWidth / bottomSlice : 1;
504
505 if (drawLeft) {
506 // Paint the top and bottom left corners.
507
508 // The top left corner rect is (tx, ty, leftWidth, topWidth)
509 // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
510 if (drawTop)
511 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.loca tion(), IntSize(leftWidth, topWidth)),
512 LayoutRect(0, 0, leftSlice, topSlice), op );
513
514 // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth)
515 // The rect to use from within the image is (0, imageHeight - bottomSlic e, leftSlice, botomSlice)
516 if (drawBottom)
517 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.x(), borderImageRect.maxY() - bottomWidth, leftWidth, bottomWidth),
518 LayoutRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice), op);
519
520 // Paint the left edge.
521 // Have to scale and tile into the border rect.
522 if (sourceHeight > 0)
523 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect .x(), borderImageRect.y() + topWidth, leftWidth, destinationHeight),
524 IntRect(0, topSlice, leftSlice, sour ceHeight),
525 FloatSize(leftSideScale, leftSideSca le), Image::StretchTile, (Image::TileRule)vRule, op);
526 }
527
528 if (drawRight) {
529 // Paint the top and bottom right corners
530 // The top right corner rect is (tx + w - rightWidth, ty, rightWidth, to pWidth)
531 // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
532 if (drawTop)
533 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.maxX () - rightWidth, borderImageRect.y(), rightWidth, topWidth),
534 LayoutRect(imageWidth - rightSlice, 0, ri ghtSlice, topSlice), op);
535
536 // The bottom right corner rect is (tx + w - rightWidth, ty + h - bottom Width, rightWidth, bottomWidth)
537 // The rect to use from within the image is (imageWidth - rightSlice, im ageHeight - bottomSlice, rightSlice, bottomSlice)
538 if (drawBottom)
539 graphicsContext->drawImage(image.get(), IntRect(borderImageRect.maxX () - rightWidth, borderImageRect.maxY() - bottomWidth, rightWidth, bottomWidth),
540 LayoutRect(imageWidth - rightSlice, image Height - bottomSlice, rightSlice, bottomSlice), op);
541
542 // Paint the right edge.
543 if (sourceHeight > 0)
544 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect .maxX() - rightWidth, borderImageRect.y() + topWidth, rightWidth,
545 destinationHeight),
546 IntRect(imageWidth - rightSlice, top Slice, rightSlice, sourceHeight),
547 FloatSize(rightSideScale, rightSideS cale),
548 Image::StretchTile, (Image::TileRule )vRule, op);
549 }
550
551 // Paint the top edge.
552 if (drawTop && sourceWidth > 0)
553 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x() + leftWidth, borderImageRect.y(), destinationWidth, topWidth),
554 IntRect(leftSlice, 0, sourceWidth, topSl ice),
555 FloatSize(topSideScale, topSideScale), ( Image::TileRule)hRule, Image::StretchTile, op);
556
557 // Paint the bottom edge.
558 if (drawBottom && sourceWidth > 0)
559 graphicsContext->drawTiledImage(image.get(), IntRect(borderImageRect.x() + leftWidth, borderImageRect.maxY() - bottomWidth,
560 destinationWidth, bottomWidth),
561 IntRect(leftSlice, imageHeight - bottomS lice, sourceWidth, bottomSlice),
562 FloatSize(bottomSideScale, bottomSideSca le),
563 (Image::TileRule)hRule, Image::StretchTi le, op);
564
565 // Paint the middle.
566 if (drawMiddle) {
567 FloatSize middleScaleFactor(1, 1);
568 if (drawTop)
569 middleScaleFactor.setWidth(topSideScale);
570 else if (drawBottom)
571 middleScaleFactor.setWidth(bottomSideScale);
572 if (drawLeft)
573 middleScaleFactor.setHeight(leftSideScale);
574 else if (drawRight)
575 middleScaleFactor.setHeight(rightSideScale);
576
577 // For "stretch" rules, just override the scale factor and replace. We o nly had to do this for the
578 // center tile, since sides don't even use the scale factor unless they have a rule other than "stretch".
579 // The middle however can have "stretch" specified in one axis but not t he other, so we have to
580 // correct the scale here.
581 if (hRule == StretchImageRule)
582 middleScaleFactor.setWidth(destinationWidth / sourceWidth);
583
584 if (vRule == StretchImageRule)
585 middleScaleFactor.setHeight(destinationHeight / sourceHeight);
586
587 graphicsContext->drawTiledImage(image.get(),
588 IntRect(borderImageRect.x() + leftWidth, borderImageRect.y() + topWi dth, destinationWidth, destinationHeight),
589 IntRect(leftSlice, topSlice, sourceWidth, sourceHeight),
590 middleScaleFactor, (Image::TileRule)hRule, (Image::TileRule)vRule, o p);
591 }
592
593 return true;
594 }
595
596 static bool allCornersClippedOut(const RoundedRect& border, const LayoutRect& cl ipRect)
597 {
598 LayoutRect boundingRect = border.rect();
599 if (clipRect.contains(boundingRect))
600 return false;
601
602 RoundedRect::Radii radii = border.radii();
603
604 LayoutRect topLeftRect(boundingRect.location(), radii.topLeft());
605 if (clipRect.intersects(topLeftRect))
606 return false;
607
608 LayoutRect topRightRect(boundingRect.location(), radii.topRight());
609 topRightRect.setX(boundingRect.maxX() - topRightRect.width());
610 if (clipRect.intersects(topRightRect))
611 return false;
612
613 LayoutRect bottomLeftRect(boundingRect.location(), radii.bottomLeft());
614 bottomLeftRect.setY(boundingRect.maxY() - bottomLeftRect.height());
615 if (clipRect.intersects(bottomLeftRect))
616 return false;
617
618 LayoutRect bottomRightRect(boundingRect.location(), radii.bottomRight());
619 bottomRightRect.setX(boundingRect.maxX() - bottomRightRect.width());
620 bottomRightRect.setY(boundingRect.maxY() - bottomRightRect.height());
621 if (clipRect.intersects(bottomRightRect))
622 return false;
623
624 return true;
625 }
626
627 static bool borderWillArcInnerEdge(const LayoutSize& firstRadius, const FloatSiz e& secondRadius)
628 {
629 return !firstRadius.isZero() || !secondRadius.isZero();
630 }
631
632 enum BorderEdgeFlag {
633 TopBorderEdge = 1 << BSTop,
634 RightBorderEdge = 1 << BSRight,
635 BottomBorderEdge = 1 << BSBottom,
636 LeftBorderEdge = 1 << BSLeft,
637 AllBorderEdges = TopBorderEdge | BottomBorderEdge | LeftBorderEdge | RightBo rderEdge
638 };
639
640 static inline BorderEdgeFlag edgeFlagForSide(BoxSide side)
641 {
642 return static_cast<BorderEdgeFlag>(1 << side);
643 }
644
645 static inline bool includesEdge(BorderEdgeFlags flags, BoxSide side)
646 {
647 return flags & edgeFlagForSide(side);
648 }
649
650 static inline bool includesAdjacentEdges(BorderEdgeFlags flags)
651 {
652 return (flags & (TopBorderEdge | RightBorderEdge)) == (TopBorderEdge | Right BorderEdge)
653 || (flags & (RightBorderEdge | BottomBorderEdge)) == (RightBorderEdge | BottomBorderEdge)
654 || (flags & (BottomBorderEdge | LeftBorderEdge)) == (BottomBorderEdge | LeftBorderEdge)
655 || (flags & (LeftBorderEdge | TopBorderEdge)) == (LeftBorderEdge | TopBo rderEdge);
656 }
657
658 inline bool styleRequiresClipPolygon(EBorderStyle style)
659 {
660 return style == DOTTED || style == DASHED; // These are drawn with a stroke, so we have to clip to get corner miters.
661 }
662
663 static bool borderStyleFillsBorderArea(EBorderStyle style)
664 {
665 return !(style == DOTTED || style == DASHED || style == DOUBLE);
666 }
667
668 static bool borderStyleHasInnerDetail(EBorderStyle style)
669 {
670 return style == GROOVE || style == RIDGE || style == DOUBLE;
671 }
672
673 static bool borderStyleIsDottedOrDashed(EBorderStyle style)
674 {
675 return style == DOTTED || style == DASHED;
676 }
677
678 // OUTSET darkens the bottom and right (and maybe lightens the top and left)
679 // INSET darkens the top and left (and maybe lightens the bottom and right)
680 static inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style, Box Side side, BoxSide adjacentSide)
681 {
682 // These styles match at the top/left and bottom/right.
683 if (style == INSET || style == GROOVE || style == RIDGE || style == OUTSET) {
684 const BorderEdgeFlags topRightFlags = edgeFlagForSide(BSTop) | edgeFlagF orSide(BSRight);
685 const BorderEdgeFlags bottomLeftFlags = edgeFlagForSide(BSBottom) | edge FlagForSide(BSLeft);
686
687 BorderEdgeFlags flags = edgeFlagForSide(side) | edgeFlagForSide(adjacent Side);
688 return flags == topRightFlags || flags == bottomLeftFlags;
689 }
690 return false;
691 }
692
693 static inline bool colorsMatchAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
694 {
695 if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
696 return false;
697
698 if (!edges[side].sharesColorWith(edges[adjacentSide]))
699 return false;
700
701 return !borderStyleHasUnmatchedColorsAtCorner(edges[side].borderStyle(), sid e, adjacentSide);
702 }
703
704
705 static inline bool colorNeedsAntiAliasAtCorner(BoxSide side, BoxSide adjacentSid e, const BorderEdge edges[])
706 {
707 if (!edges[side].color.hasAlpha())
708 return false;
709
710 if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
711 return false;
712
713 if (!edges[side].sharesColorWith(edges[adjacentSide]))
714 return true;
715
716 return borderStyleHasUnmatchedColorsAtCorner(edges[side].borderStyle(), side , adjacentSide);
717 }
718
719 // This assumes that we draw in order: top, bottom, left, right.
720 static inline bool willBeOverdrawn(BoxSide side, BoxSide adjacentSide, const Bor derEdge edges[])
721 {
722 switch (side) {
723 case BSTop:
724 case BSBottom:
725 if (edges[adjacentSide].presentButInvisible())
726 return false;
727
728 if (!edges[side].sharesColorWith(edges[adjacentSide]) && edges[adjacentS ide].color.hasAlpha())
729 return false;
730
731 if (!borderStyleFillsBorderArea(edges[adjacentSide].borderStyle()))
732 return false;
733
734 return true;
735
736 case BSLeft:
737 case BSRight:
738 // These draw last, so are never overdrawn.
739 return false;
740 }
741 return false;
742 }
743
744 static inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorderStyle style, EBorderStyle adjacentStyle)
745 {
746 if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE || adjacentStyle == RIDGE)
747 return true;
748
749 if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjace ntStyle))
750 return true;
751
752 if (style != adjacentStyle)
753 return true;
754
755 return borderStyleHasUnmatchedColorsAtCorner(style, side, adjacentSide);
756 }
757
758 static bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEd ge edges[], bool allowOverdraw)
759 {
760 if ((edges[side].isTransparent && edges[adjacentSide].isTransparent) || !edg es[adjacentSide].isPresent)
761 return false;
762
763 if (allowOverdraw && willBeOverdrawn(side, adjacentSide, edges))
764 return false;
765
766 if (!edges[side].sharesColorWith(edges[adjacentSide]))
767 return true;
768
769 if (borderStylesRequireMitre(side, adjacentSide, edges[side].borderStyle(), edges[adjacentSide].borderStyle()))
770 return true;
771
772 return false;
773 }
774
775 void RenderBoxModelObject::paintOneBorderSide(GraphicsContext* graphicsContext, const RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& inn erBorder,
776 const IntRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adjace ntSide2, const BorderEdge edges[], const Path* path,
777 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool i ncludeLogicalRightEdge, bool antialias, const Color* overrideColor)
778 {
779 const BorderEdge& edgeToRender = edges[side];
780 ASSERT(edgeToRender.width);
781 const BorderEdge& adjacentEdge1 = edges[adjacentSide1];
782 const BorderEdge& adjacentEdge2 = edges[adjacentSide2];
783
784 bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, edges, !ant ialias);
785 bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, edges, !ant ialias);
786
787 bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, edg es);
788 bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, edg es);
789
790 const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.co lor;
791
792 if (path) {
793 GraphicsContextStateSaver stateSaver(*graphicsContext);
794 if (innerBorder.isRenderable())
795 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, sid e, adjacentSide1StylesMatch, adjacentSide2StylesMatch);
796 else
797 clipBorderSideForComplexInnerPath(graphicsContext, outerBorder, inne rBorder, side, edges);
798 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi dth), adjacentEdge2.width);
799 drawBoxSideFromPath(graphicsContext, outerBorder.rect(), *path, edges, e dgeToRender.width, thickness, side, style,
800 colorToPaint, edgeToRender.borderStyle(), bleedAvoidance, includeLog icalLeftEdge, includeLogicalRightEdge);
801 } else {
802 bool clipForStyle = styleRequiresClipPolygon(edgeToRender.borderStyle()) && (mitreAdjacentSide1 || mitreAdjacentSide2);
803 bool clipAdjacentSide1 = colorNeedsAntiAliasAtCorner(side, adjacentSide1 , edges) && mitreAdjacentSide1;
804 bool clipAdjacentSide2 = colorNeedsAntiAliasAtCorner(side, adjacentSide2 , edges) && mitreAdjacentSide2;
805 bool shouldClip = clipForStyle || clipAdjacentSide1 || clipAdjacentSide2 ;
806
807 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip);
808 if (shouldClip) {
809 bool aliasAdjacentSide1 = clipAdjacentSide1 || (clipForStyle && mitr eAdjacentSide1);
810 bool aliasAdjacentSide2 = clipAdjacentSide2 || (clipForStyle && mitr eAdjacentSide2);
811 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, sid e, !aliasAdjacentSide1, !aliasAdjacentSide2);
812 // Since we clipped, no need to draw with a mitre.
813 mitreAdjacentSide1 = false;
814 mitreAdjacentSide2 = false;
815 }
816
817 drawLineForBoxSide(graphicsContext, sideRect.x(), sideRect.y(), sideRect .maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.borderStyle(),
818 mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? adjacentEdge2.width : 0, antialias);
819 }
820 }
821
822 static IntRect calculateSideRect(const RoundedRect& outerBorder, const BorderEdg e edges[], int side)
823 {
824 IntRect sideRect = outerBorder.rect();
825 int width = edges[side].width;
826
827 if (side == BSTop)
828 sideRect.setHeight(width);
829 else if (side == BSBottom)
830 sideRect.shiftYEdgeTo(sideRect.maxY() - width);
831 else if (side == BSLeft)
832 sideRect.setWidth(width);
833 else
834 sideRect.shiftXEdgeTo(sideRect.maxX() - width);
835
836 return sideRect;
837 }
838
839 void RenderBoxModelObject::paintBorderSides(GraphicsContext* graphicsContext, co nst RenderStyle* style, const RoundedRect& outerBorder, const RoundedRect& inner Border,
840 const IntPoint& innerBorderAdjustment, const BorderEdge edges[], BorderEdgeF lags edgeSet, BackgroundBleedAvoidance bleedAvoidance,
841 bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, c onst Color* overrideColor)
842 {
843 bool renderRadii = outerBorder.isRounded();
844
845 Path roundedPath;
846 if (renderRadii)
847 roundedPath.addRoundedRect(outerBorder);
848
849 // The inner border adjustment for bleed avoidance mode BackgroundBleedBackg roundOverBorder
850 // is only applied to sideRect, which is okay since BackgroundBleedBackgroun dOverBorder
851 // is only to be used for solid borders and the shape of the border painted by drawBoxSideFromPath
852 // only depends on sideRect when painting solid borders.
853
854 if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) {
855 IntRect sideRect = outerBorder.rect();
856 sideRect.setHeight(edges[BSTop].width + innerBorderAdjustment.y());
857
858 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].bo rderStyle()) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorde r.radii().topRight()));
859 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance , includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
860 }
861
862 if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) {
863 IntRect sideRect = outerBorder.rect();
864 sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width - innerBor derAdjustment.y());
865
866 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom] .borderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), inne rBorder.radii().bottomRight()));
867 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoida nce, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
868 }
869
870 if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) {
871 IntRect sideRect = outerBorder.rect();
872 sideRect.setWidth(edges[BSLeft].width + innerBorderAdjustment.x());
873
874 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].b orderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerB order.radii().topLeft()));
875 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidanc e, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
876 }
877
878 if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) {
879 IntRect sideRect = outerBorder.rect();
880 sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width - innerBord erAdjustment.x());
881
882 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight]. borderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), inne rBorder.radii().topRight()));
883 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid eRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidan ce, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
884 }
885 }
886
887 void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext* graphics Context, const RenderStyle* style, const RoundedRect& outerBorder, const Rounded Rect& innerBorder, const IntPoint& innerBorderAdjustment,
888 const BorderEdge edges[], BorderEdgeFlags edgesToDraw, BackgroundBleedAvoida nce bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, b ool antialias)
889 {
890 // willBeOverdrawn assumes that we draw in order: top, bottom, left, right.
891 // This is different from BoxSide enum order.
892 static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight };
893
894 while (edgesToDraw) {
895 // Find undrawn edges sharing a color.
896 Color commonColor;
897
898 BorderEdgeFlags commonColorEdgeSet = 0;
899 for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i) {
900 BoxSide currSide = paintOrder[i];
901 if (!includesEdge(edgesToDraw, currSide))
902 continue;
903
904 bool includeEdge;
905 if (!commonColorEdgeSet) {
906 commonColor = edges[currSide].color;
907 includeEdge = true;
908 } else
909 includeEdge = edges[currSide].color == commonColor;
910
911 if (includeEdge)
912 commonColorEdgeSet |= edgeFlagForSide(currSide);
913 }
914
915 bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) && commonColor.hasAlpha();
916 if (useTransparencyLayer) {
917 graphicsContext->beginTransparencyLayer(static_cast<float>(commonCol or.alpha()) / 255);
918 commonColor = Color(commonColor.red(), commonColor.green(), commonCo lor.blue());
919 }
920
921 paintBorderSides(graphicsContext, style, outerBorder, innerBorder, inner BorderAdjustment, edges, commonColorEdgeSet, bleedAvoidance, includeLogicalLeftE dge, includeLogicalRightEdge, antialias, &commonColor);
922
923 if (useTransparencyLayer)
924 graphicsContext->endLayer();
925
926 edgesToDraw &= ~commonColorEdgeSet;
927 }
928 }
929
930 void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& rect, const RenderStyle* style,
931 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
932 {
933 GraphicsContext* graphicsContext = info.context;
934 // border-image is not affected by border-radius.
935 if (paintNinePieceImage(graphicsContext, rect, style, style->borderImage()))
936 return;
937
938 BorderEdge edges[4];
939 style->getBorderEdgeInfo(edges, includeLogicalLeftEdge, includeLogicalRightE dge);
940 RoundedRect outerBorder = style->getRoundedBorderFor(rect, includeLogicalLef tEdge, includeLogicalRightEdge);
941 RoundedRect innerBorder = style->getRoundedInnerBorderFor(borderInnerRectAdj ustedForBleedAvoidance(graphicsContext, rect, bleedAvoidance), includeLogicalLef tEdge, includeLogicalRightEdge);
942
943 if (outerBorder.rect().isEmpty())
944 return;
945
946 bool haveAlphaColor = false;
947 bool haveAllSolidEdges = true;
948 bool haveAllDoubleEdges = true;
949 int numEdgesVisible = 4;
950 bool allEdgesShareColor = true;
951 bool allEdgesShareWidth = true;
952 int firstVisibleEdge = -1;
953 BorderEdgeFlags edgesToDraw = 0;
954
955 for (int i = BSTop; i <= BSLeft; ++i) {
956 const BorderEdge& currEdge = edges[i];
957
958 if (edges[i].shouldRender())
959 edgesToDraw |= edgeFlagForSide(static_cast<BoxSide>(i));
960
961 if (currEdge.presentButInvisible()) {
962 --numEdgesVisible;
963 allEdgesShareColor = false;
964 allEdgesShareWidth = false;
965 continue;
966 }
967
968 if (!currEdge.shouldRender()) {
969 --numEdgesVisible;
970 continue;
971 }
972
973 if (firstVisibleEdge == -1) {
974 firstVisibleEdge = i;
975 } else {
976 if (currEdge.color != edges[firstVisibleEdge].color)
977 allEdgesShareColor = false;
978 if (currEdge.width != edges[firstVisibleEdge].width)
979 allEdgesShareWidth = false;
980 }
981
982 if (currEdge.color.hasAlpha())
983 haveAlphaColor = true;
984
985 if (currEdge.borderStyle() != SOLID)
986 haveAllSolidEdges = false;
987
988 if (currEdge.borderStyle() != DOUBLE)
989 haveAllDoubleEdges = false;
990 }
991
992 // If no corner intersects the clip region, we can pretend outerBorder is
993 // rectangular to improve performance.
994 if (haveAllSolidEdges && outerBorder.isRounded() && allCornersClippedOut(out erBorder, info.rect))
995 outerBorder.setRadii(RoundedRect::Radii());
996
997 // isRenderable() check avoids issue described in https://bugs.webkit.org/sh ow_bug.cgi?id=38787
998 if ((haveAllSolidEdges || haveAllDoubleEdges) && allEdgesShareColor && inner Border.isRenderable()) {
999 // Fast path for drawing all solid edges and all unrounded double edges
1000
1001 if (numEdgesVisible == 4 && (outerBorder.isRounded() || haveAlphaColor)
1002 && (haveAllSolidEdges || (!outerBorder.isRounded() && !innerBorder.i sRounded()))) {
1003 Path path;
1004
1005 if (outerBorder.isRounded() && allEdgesShareWidth) {
1006
1007 // Very fast path for single stroked round rect with circular co rners
1008
1009 graphicsContext->fillBetweenRoundedRects(outerBorder, innerBorde r, edges[firstVisibleEdge].color);
1010 return;
1011 }
1012 if (outerBorder.isRounded() && bleedAvoidance != BackgroundBleedClip Background)
1013 path.addRoundedRect(outerBorder);
1014 else
1015 path.addRect(outerBorder.rect());
1016
1017 if (haveAllDoubleEdges) {
1018 IntRect innerThirdRect = outerBorder.rect();
1019 IntRect outerThirdRect = outerBorder.rect();
1020 for (int side = BSTop; side <= BSLeft; ++side) {
1021 int outerWidth;
1022 int innerWidth;
1023 edges[side].getDoubleBorderStripeWidths(outerWidth, innerWid th);
1024
1025 if (side == BSTop) {
1026 innerThirdRect.shiftYEdgeTo(innerThirdRect.y() + innerWi dth);
1027 outerThirdRect.shiftYEdgeTo(outerThirdRect.y() + outerWi dth);
1028 } else if (side == BSBottom) {
1029 innerThirdRect.setHeight(innerThirdRect.height() - inner Width);
1030 outerThirdRect.setHeight(outerThirdRect.height() - outer Width);
1031 } else if (side == BSLeft) {
1032 innerThirdRect.shiftXEdgeTo(innerThirdRect.x() + innerWi dth);
1033 outerThirdRect.shiftXEdgeTo(outerThirdRect.x() + outerWi dth);
1034 } else {
1035 innerThirdRect.setWidth(innerThirdRect.width() - innerWi dth);
1036 outerThirdRect.setWidth(outerThirdRect.width() - outerWi dth);
1037 }
1038 }
1039
1040 RoundedRect outerThird = outerBorder;
1041 RoundedRect innerThird = innerBorder;
1042 innerThird.setRect(innerThirdRect);
1043 outerThird.setRect(outerThirdRect);
1044
1045 if (outerThird.isRounded() && bleedAvoidance != BackgroundBleedC lipBackground)
1046 path.addRoundedRect(outerThird);
1047 else
1048 path.addRect(outerThird.rect());
1049
1050 if (innerThird.isRounded() && bleedAvoidance != BackgroundBleedC lipBackground)
1051 path.addRoundedRect(innerThird);
1052 else
1053 path.addRect(innerThird.rect());
1054 }
1055
1056 if (innerBorder.isRounded())
1057 path.addRoundedRect(innerBorder);
1058 else
1059 path.addRect(innerBorder.rect());
1060
1061 graphicsContext->setFillRule(RULE_EVENODD);
1062 graphicsContext->setFillColor(edges[firstVisibleEdge].color);
1063 graphicsContext->fillPath(path);
1064 return;
1065 }
1066 // Avoid creating transparent layers
1067 if (haveAllSolidEdges && numEdgesVisible != 4 && !outerBorder.isRounded( ) && haveAlphaColor) {
1068 Path path;
1069
1070 for (int i = BSTop; i <= BSLeft; ++i) {
1071 const BorderEdge& currEdge = edges[i];
1072 if (currEdge.shouldRender()) {
1073 IntRect sideRect = calculateSideRect(outerBorder, edges, i);
1074 path.addRect(sideRect);
1075 }
1076 }
1077
1078 graphicsContext->setFillRule(RULE_NONZERO);
1079 graphicsContext->setFillColor(edges[firstVisibleEdge].color);
1080 graphicsContext->fillPath(path);
1081 return;
1082 }
1083 }
1084
1085 bool clipToOuterBorder = outerBorder.isRounded();
1086 GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder);
1087 if (clipToOuterBorder) {
1088 // Clip to the inner and outer radii rects.
1089 if (bleedAvoidance != BackgroundBleedClipBackground)
1090 graphicsContext->clipRoundedRect(outerBorder);
1091 // isRenderable() check avoids issue described in https://bugs.webkit.or g/show_bug.cgi?id=38787
1092 // The inside will be clipped out later (in clipBorderSideForComplexInne rPath)
1093 if (innerBorder.isRenderable() && !innerBorder.isEmpty())
1094 graphicsContext->clipOutRoundedRect(innerBorder);
1095 }
1096
1097 // If only one edge visible antialiasing doesn't create seams
1098 bool antialias = shouldAntialiasLines(graphicsContext) || numEdgesVisible == 1;
1099 RoundedRect unadjustedInnerBorder = (bleedAvoidance == BackgroundBleedBackgr oundOverBorder) ? style->getRoundedInnerBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge) : innerBorder;
1100 IntPoint innerBorderAdjustment(innerBorder.rect().x() - unadjustedInnerBorde r.rect().x(), innerBorder.rect().y() - unadjustedInnerBorder.rect().y());
1101 if (haveAlphaColor)
1102 paintTranslucentBorderSides(graphicsContext, style, outerBorder, unadjus tedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, inclu deLogicalLeftEdge, includeLogicalRightEdge, antialias);
1103 else
1104 paintBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBor der, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLe ftEdge, includeLogicalRightEdge, antialias);
1105 }
1106
1107 void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, const LayoutRect& borderRect, const Path& borderPath, const BorderEdge edges[],
1108 float thickness, float drawThickness, BoxSide side, const RenderStyle* style , Color color, EBorderStyle borderStyle, BackgroundBleedAvoidance bleedAvoidance ,
1109 bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1110 {
1111 if (thickness <= 0)
1112 return;
1113
1114 if (borderStyle == DOUBLE && thickness < 3)
1115 borderStyle = SOLID;
1116
1117 switch (borderStyle) {
1118 case BNONE:
1119 case BHIDDEN:
1120 return;
1121 case DOTTED:
1122 case DASHED: {
1123 graphicsContext->setStrokeColor(color);
1124
1125 // The stroke is doubled here because the provided path is the
1126 // outside edge of the border so half the stroke is clipped off.
1127 // The extra multiplier is so that the clipping mask can antialias
1128 // the edges to prevent jaggies.
1129 graphicsContext->setStrokeThickness(drawThickness * 2 * 1.1f);
1130 graphicsContext->setStrokeStyle(borderStyle == DASHED ? DashedStroke : D ottedStroke);
1131
1132 // If the number of dashes that fit in the path is odd and non-integral then we
1133 // will have an awkwardly-sized dash at the end of the path. To try to a void that
1134 // here, we simply make the whitespace dashes ever so slightly bigger.
1135 // FIXME: This could be even better if we tried to manipulate the dash o ffset
1136 // and possibly the gapLength to get the corners dash-symmetrical.
1137 float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f);
1138 float gapLength = dashLength;
1139 float numberOfDashes = borderPath.length() / dashLength;
1140 // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
1141 // FIXME: should do this test per side.
1142 if (numberOfDashes >= 4) {
1143 bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
1144 bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes );
1145 if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
1146 float numberOfGaps = numberOfDashes / 2;
1147 gapLength += (dashLength / numberOfGaps);
1148 }
1149
1150 DashArray lineDash;
1151 lineDash.append(dashLength);
1152 lineDash.append(gapLength);
1153 graphicsContext->setLineDash(lineDash, dashLength);
1154 }
1155
1156 // FIXME: stroking the border path causes issues with tight corners:
1157 // https://bugs.webkit.org/show_bug.cgi?id=58711
1158 // Also, to get the best appearance we should stroke a path between the two borders.
1159 graphicsContext->strokePath(borderPath);
1160 return;
1161 }
1162 case DOUBLE: {
1163 // Get the inner border rects for both the outer border line and the inn er border line
1164 int outerBorderTopWidth;
1165 int innerBorderTopWidth;
1166 edges[BSTop].getDoubleBorderStripeWidths(outerBorderTopWidth, innerBorde rTopWidth);
1167
1168 int outerBorderRightWidth;
1169 int innerBorderRightWidth;
1170 edges[BSRight].getDoubleBorderStripeWidths(outerBorderRightWidth, innerB orderRightWidth);
1171
1172 int outerBorderBottomWidth;
1173 int innerBorderBottomWidth;
1174 edges[BSBottom].getDoubleBorderStripeWidths(outerBorderBottomWidth, inne rBorderBottomWidth);
1175
1176 int outerBorderLeftWidth;
1177 int innerBorderLeftWidth;
1178 edges[BSLeft].getDoubleBorderStripeWidths(outerBorderLeftWidth, innerBor derLeftWidth);
1179
1180 // Draw inner border line
1181 {
1182 GraphicsContextStateSaver stateSaver(*graphicsContext);
1183 RoundedRect innerClip = style->getRoundedInnerBorderFor(borderRect,
1184 innerBorderTopWidth, innerBorderBottomWidth, innerBorderLeftWidt h, innerBorderRightWidth,
1185 includeLogicalLeftEdge, includeLogicalRightEdge);
1186
1187 graphicsContext->clipRoundedRect(innerClip);
1188 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogi calLeftEdge, includeLogicalRightEdge);
1189 }
1190
1191 // Draw outer border line
1192 {
1193 GraphicsContextStateSaver stateSaver(*graphicsContext);
1194 LayoutRect outerRect = borderRect;
1195 if (bleedAvoidance == BackgroundBleedClipBackground) {
1196 outerRect.inflate(1);
1197 ++outerBorderTopWidth;
1198 ++outerBorderBottomWidth;
1199 ++outerBorderLeftWidth;
1200 ++outerBorderRightWidth;
1201 }
1202
1203 RoundedRect outerClip = style->getRoundedInnerBorderFor(outerRect,
1204 outerBorderTopWidth, outerBorderBottomWidth, outerBorderLeftWidt h, outerBorderRightWidth,
1205 includeLogicalLeftEdge, includeLogicalRightEdge);
1206 graphicsContext->clipOutRoundedRect(outerClip);
1207 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogi calLeftEdge, includeLogicalRightEdge);
1208 }
1209 return;
1210 }
1211 case RIDGE:
1212 case GROOVE:
1213 {
1214 EBorderStyle s1;
1215 EBorderStyle s2;
1216 if (borderStyle == GROOVE) {
1217 s1 = INSET;
1218 s2 = OUTSET;
1219 } else {
1220 s1 = OUTSET;
1221 s2 = INSET;
1222 }
1223
1224 // Paint full border
1225 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thic kness, drawThickness, side, style, color, s1, bleedAvoidance, includeLogicalLeft Edge, includeLogicalRightEdge);
1226
1227 // Paint inner only
1228 GraphicsContextStateSaver stateSaver(*graphicsContext);
1229 LayoutUnit topWidth = edges[BSTop].usedWidth() / 2;
1230 LayoutUnit bottomWidth = edges[BSBottom].usedWidth() / 2;
1231 LayoutUnit leftWidth = edges[BSLeft].usedWidth() / 2;
1232 LayoutUnit rightWidth = edges[BSRight].usedWidth() / 2;
1233
1234 RoundedRect clipRect = style->getRoundedInnerBorderFor(borderRect,
1235 topWidth, bottomWidth, leftWidth, rightWidth,
1236 includeLogicalLeftEdge, includeLogicalRightEdge);
1237
1238 graphicsContext->clipRoundedRect(clipRect);
1239 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thic kness, drawThickness, side, style, color, s2, bleedAvoidance, includeLogicalLeft Edge, includeLogicalRightEdge);
1240 return;
1241 }
1242 case INSET:
1243 if (side == BSTop || side == BSLeft)
1244 color = color.dark();
1245 break;
1246 case OUTSET:
1247 if (side == BSBottom || side == BSRight)
1248 color = color.dark();
1249 break;
1250 default:
1251 break;
1252 }
1253
1254 graphicsContext->setStrokeStyle(NoStroke);
1255 graphicsContext->setFillColor(color);
1256 graphicsContext->drawRect(pixelSnappedIntRect(borderRect));
1257 }
1258
1259 void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext* graphicsContex t, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
1260 BoxSide side, bool firstEdgeMat ches, bool secondEdgeMatches)
1261 {
1262 FloatPoint quad[4];
1263
1264 const LayoutRect& outerRect = outerBorder.rect();
1265 const LayoutRect& innerRect = innerBorder.rect();
1266
1267 FloatPoint centerPoint(innerRect.location().x().toFloat() + innerRect.width( ).toFloat() / 2, innerRect.location().y().toFloat() + innerRect.height().toFloat () / 2);
1268
1269 // For each side, create a quad that encompasses all parts of that side that may draw,
1270 // including areas inside the innerBorder.
1271 //
1272 // 0----------------3
1273 // 0 \ / 0
1274 // |\ 1----------- 2 /|
1275 // | 1 1 |
1276 // | | | |
1277 // | | | |
1278 // | 2 2 |
1279 // |/ 1------------2 \|
1280 // 3 / \ 3
1281 // 0----------------3
1282 //
1283 switch (side) {
1284 case BSTop:
1285 quad[0] = outerRect.minXMinYCorner();
1286 quad[1] = innerRect.minXMinYCorner();
1287 quad[2] = innerRect.maxXMinYCorner();
1288 quad[3] = outerRect.maxXMinYCorner();
1289
1290 if (!innerBorder.radii().topLeft().isZero()) {
1291 findIntersection(quad[0], quad[1],
1292 FloatPoint(
1293 quad[1].x() + innerBorder.radii().topLeft().width(),
1294 quad[1].y()),
1295 FloatPoint(
1296 quad[1].x(),
1297 quad[1].y() + innerBorder.radii().topLeft().height()),
1298 quad[1]);
1299 }
1300
1301 if (!innerBorder.radii().topRight().isZero()) {
1302 findIntersection(quad[3], quad[2],
1303 FloatPoint(
1304 quad[2].x() - innerBorder.radii().topRight().width(),
1305 quad[2].y()),
1306 FloatPoint(
1307 quad[2].x(),
1308 quad[2].y() + innerBorder.radii().topRight().height()),
1309 quad[2]);
1310 }
1311 break;
1312
1313 case BSLeft:
1314 quad[0] = outerRect.minXMinYCorner();
1315 quad[1] = innerRect.minXMinYCorner();
1316 quad[2] = innerRect.minXMaxYCorner();
1317 quad[3] = outerRect.minXMaxYCorner();
1318
1319 if (!innerBorder.radii().topLeft().isZero()) {
1320 findIntersection(quad[0], quad[1],
1321 FloatPoint(
1322 quad[1].x() + innerBorder.radii().topLeft().width(),
1323 quad[1].y()),
1324 FloatPoint(
1325 quad[1].x(),
1326 quad[1].y() + innerBorder.radii().topLeft().height()),
1327 quad[1]);
1328 }
1329
1330 if (!innerBorder.radii().bottomLeft().isZero()) {
1331 findIntersection(quad[3], quad[2],
1332 FloatPoint(
1333 quad[2].x() + innerBorder.radii().bottomLeft().width(),
1334 quad[2].y()),
1335 FloatPoint(
1336 quad[2].x(),
1337 quad[2].y() - innerBorder.radii().bottomLeft().height()),
1338 quad[2]);
1339 }
1340 break;
1341
1342 case BSBottom:
1343 quad[0] = outerRect.minXMaxYCorner();
1344 quad[1] = innerRect.minXMaxYCorner();
1345 quad[2] = innerRect.maxXMaxYCorner();
1346 quad[3] = outerRect.maxXMaxYCorner();
1347
1348 if (!innerBorder.radii().bottomLeft().isZero()) {
1349 findIntersection(quad[0], quad[1],
1350 FloatPoint(
1351 quad[1].x() + innerBorder.radii().bottomLeft().width(),
1352 quad[1].y()),
1353 FloatPoint(
1354 quad[1].x(),
1355 quad[1].y() - innerBorder.radii().bottomLeft().height()),
1356 quad[1]);
1357 }
1358
1359 if (!innerBorder.radii().bottomRight().isZero()) {
1360 findIntersection(quad[3], quad[2],
1361 FloatPoint(
1362 quad[2].x() - innerBorder.radii().bottomRight().width(),
1363 quad[2].y()),
1364 FloatPoint(
1365 quad[2].x(),
1366 quad[2].y() - innerBorder.radii().bottomRight().height()),
1367 quad[2]);
1368 }
1369 break;
1370
1371 case BSRight:
1372 quad[0] = outerRect.maxXMinYCorner();
1373 quad[1] = innerRect.maxXMinYCorner();
1374 quad[2] = innerRect.maxXMaxYCorner();
1375 quad[3] = outerRect.maxXMaxYCorner();
1376
1377 if (!innerBorder.radii().topRight().isZero()) {
1378 findIntersection(quad[0], quad[1],
1379 FloatPoint(
1380 quad[1].x() - innerBorder.radii().topRight().width(),
1381 quad[1].y()),
1382 FloatPoint(
1383 quad[1].x(),
1384 quad[1].y() + innerBorder.radii().topRight().height()),
1385 quad[1]);
1386 }
1387
1388 if (!innerBorder.radii().bottomRight().isZero()) {
1389 findIntersection(quad[3], quad[2],
1390 FloatPoint(
1391 quad[2].x() - innerBorder.radii().bottomRight().width(),
1392 quad[2].y()),
1393 FloatPoint(
1394 quad[2].x(),
1395 quad[2].y() - innerBorder.radii().bottomRight().height()),
1396 quad[2]);
1397 }
1398 break;
1399 }
1400
1401 // If the border matches both of its adjacent sides, don't anti-alias the cl ip, and
1402 // if neither side matches, anti-alias the clip.
1403 if (firstEdgeMatches == secondEdgeMatches) {
1404 graphicsContext->clipConvexPolygon(4, quad, !firstEdgeMatches);
1405 return;
1406 }
1407
1408 // If antialiasing settings for the first edge and second edge is different,
1409 // they have to be addressed separately. We do this by breaking the quad int o
1410 // two parallelograms, made by moving quad[1] and quad[2].
1411 float ax = quad[1].x() - quad[0].x();
1412 float ay = quad[1].y() - quad[0].y();
1413 float bx = quad[2].x() - quad[1].x();
1414 float by = quad[2].y() - quad[1].y();
1415 float cx = quad[3].x() - quad[2].x();
1416 float cy = quad[3].y() - quad[2].y();
1417
1418 const static float kEpsilon = 1e-2f;
1419 float r1, r2;
1420 if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) {
1421 // The quad was actually a triangle.
1422 r1 = r2 = 1.0f;
1423 } else {
1424 // Extend parallelogram a bit to hide calculation error
1425 const static float kExtendFill = 1e-2f;
1426
1427 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill;
1428 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill;
1429 }
1430
1431 FloatPoint firstQuad[4];
1432 firstQuad[0] = quad[0];
1433 firstQuad[1] = quad[1];
1434 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay);
1435 firstQuad[3] = quad[3];
1436 graphicsContext->clipConvexPolygon(4, firstQuad, !firstEdgeMatches);
1437
1438 FloatPoint secondQuad[4];
1439 secondQuad[0] = quad[0];
1440 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy);
1441 secondQuad[2] = quad[2];
1442 secondQuad[3] = quad[3];
1443 graphicsContext->clipConvexPolygon(4, secondQuad, !secondEdgeMatches);
1444 }
1445
1446 static IntRect calculateSideRectIncludingInner(const RoundedRect& outerBorder, c onst BorderEdge edges[], BoxSide side)
1447 {
1448 IntRect sideRect = outerBorder.rect();
1449 int width;
1450
1451 switch (side) {
1452 case BSTop:
1453 width = sideRect.height() - edges[BSBottom].width;
1454 sideRect.setHeight(width);
1455 break;
1456 case BSBottom:
1457 width = sideRect.height() - edges[BSTop].width;
1458 sideRect.shiftYEdgeTo(sideRect.maxY() - width);
1459 break;
1460 case BSLeft:
1461 width = sideRect.width() - edges[BSRight].width;
1462 sideRect.setWidth(width);
1463 break;
1464 case BSRight:
1465 width = sideRect.width() - edges[BSLeft].width;
1466 sideRect.shiftXEdgeTo(sideRect.maxX() - width);
1467 break;
1468 }
1469
1470 return sideRect;
1471 }
1472
1473 static RoundedRect calculateAdjustedInnerBorder(const RoundedRect&innerBorder, B oxSide side)
1474 {
1475 // Expand the inner border as necessary to make it a rounded rect (i.e. radi i contained within each edge).
1476 // This function relies on the fact we only get radii not contained within e ach edge if one of the radii
1477 // for an edge is zero, so we can shift the arc towards the zero radius corn er.
1478 RoundedRect::Radii newRadii = innerBorder.radii();
1479 IntRect newRect = innerBorder.rect();
1480
1481 float overshoot;
1482 float maxRadii;
1483
1484 switch (side) {
1485 case BSTop:
1486 overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - n ewRect.width();
1487 if (overshoot > 0) {
1488 ASSERT(!(newRadii.topLeft().width() && newRadii.topRight().width())) ;
1489 newRect.setWidth(newRect.width() + overshoot);
1490 if (!newRadii.topLeft().width())
1491 newRect.move(-overshoot, 0);
1492 }
1493 newRadii.setBottomLeft(IntSize(0, 0));
1494 newRadii.setBottomRight(IntSize(0, 0));
1495 maxRadii = std::max(newRadii.topLeft().height(), newRadii.topRight().hei ght());
1496 if (maxRadii > newRect.height())
1497 newRect.setHeight(maxRadii);
1498 break;
1499
1500 case BSBottom:
1501 overshoot = newRadii.bottomLeft().width() + newRadii.bottomRight().width () - newRect.width();
1502 if (overshoot > 0) {
1503 ASSERT(!(newRadii.bottomLeft().width() && newRadii.bottomRight().wid th()));
1504 newRect.setWidth(newRect.width() + overshoot);
1505 if (!newRadii.bottomLeft().width())
1506 newRect.move(-overshoot, 0);
1507 }
1508 newRadii.setTopLeft(IntSize(0, 0));
1509 newRadii.setTopRight(IntSize(0, 0));
1510 maxRadii = std::max(newRadii.bottomLeft().height(), newRadii.bottomRight ().height());
1511 if (maxRadii > newRect.height()) {
1512 newRect.move(0, newRect.height() - maxRadii);
1513 newRect.setHeight(maxRadii);
1514 }
1515 break;
1516
1517 case BSLeft:
1518 overshoot = newRadii.topLeft().height() + newRadii.bottomLeft().height() - newRect.height();
1519 if (overshoot > 0) {
1520 ASSERT(!(newRadii.topLeft().height() && newRadii.bottomLeft().height ()));
1521 newRect.setHeight(newRect.height() + overshoot);
1522 if (!newRadii.topLeft().height())
1523 newRect.move(0, -overshoot);
1524 }
1525 newRadii.setTopRight(IntSize(0, 0));
1526 newRadii.setBottomRight(IntSize(0, 0));
1527 maxRadii = std::max(newRadii.topLeft().width(), newRadii.bottomLeft().wi dth());
1528 if (maxRadii > newRect.width())
1529 newRect.setWidth(maxRadii);
1530 break;
1531
1532 case BSRight:
1533 overshoot = newRadii.topRight().height() + newRadii.bottomRight().height () - newRect.height();
1534 if (overshoot > 0) {
1535 ASSERT(!(newRadii.topRight().height() && newRadii.bottomRight().heig ht()));
1536 newRect.setHeight(newRect.height() + overshoot);
1537 if (!newRadii.topRight().height())
1538 newRect.move(0, -overshoot);
1539 }
1540 newRadii.setTopLeft(IntSize(0, 0));
1541 newRadii.setBottomLeft(IntSize(0, 0));
1542 maxRadii = std::max(newRadii.topRight().width(), newRadii.bottomRight(). width());
1543 if (maxRadii > newRect.width()) {
1544 newRect.move(newRect.width() - maxRadii, 0);
1545 newRect.setWidth(maxRadii);
1546 }
1547 break;
1548 }
1549
1550 return RoundedRect(newRect, newRadii);
1551 }
1552
1553 void RenderBoxModelObject::clipBorderSideForComplexInnerPath(GraphicsContext* gr aphicsContext, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
1554 BoxSide side, const BorderEdge edges[])
1555 {
1556 graphicsContext->clip(calculateSideRectIncludingInner(outerBorder, edges, si de));
1557 RoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(innerBorder, si de);
1558 if (!adjustedInnerRect.isEmpty())
1559 graphicsContext->clipOutRoundedRect(adjustedInnerRect);
1560 }
1561
1562 bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedA voidance bleedAvoidance, InlineFlowBox* inlineFlowBox) const 404 bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedA voidance bleedAvoidance, InlineFlowBox* inlineFlowBox) const
1563 { 405 {
1564 if (bleedAvoidance != BackgroundBleedNone) 406 if (bleedAvoidance != BackgroundBleedNone)
1565 return false; 407 return false;
1566 408
1567 if (style()->hasAppearance()) 409 if (style()->hasAppearance())
1568 return false; 410 return false;
1569 411
1570 const ShadowList* shadowList = style()->boxShadow(); 412 const ShadowList* shadowList = style()->boxShadow();
1571 if (!shadowList) 413 if (!shadowList)
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1605 447
1606 if (inlineFlowBox && !inlineFlowBox->boxShadowCanBeAppliedToBackground(*last BackgroundLayer)) 448 if (inlineFlowBox && !inlineFlowBox->boxShadowCanBeAppliedToBackground(*last BackgroundLayer))
1607 return false; 449 return false;
1608 450
1609 if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroun dAttachment) 451 if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroun dAttachment)
1610 return false; 452 return false;
1611 453
1612 return true; 454 return true;
1613 } 455 }
1614 456
1615 void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRec t& paintRect, const RenderStyle* s, ShadowStyle shadowStyle, bool includeLogical LeftEdge, bool includeLogicalRightEdge)
1616 {
1617 // FIXME: Deal with border-image. Would be great to use border-image as a m ask.
1618 GraphicsContext* context = info.context;
1619 if (!s->boxShadow())
1620 return;
1621 457
1622 RoundedRect border = (shadowStyle == Inset) ? s->getRoundedInnerBorderFor(pa intRect, includeLogicalLeftEdge, includeLogicalRightEdge)
1623 : s->getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLogic alRightEdge);
1624
1625 bool hasBorderRadius = s->hasBorderRadius();
1626 bool isHorizontal = s->isHorizontalWritingMode();
1627 bool hasOpaqueBackground = s->visitedDependentColor(CSSPropertyBackgroundCol or).alpha() == 255;
1628
1629 GraphicsContextStateSaver stateSaver(*context, false);
1630
1631 const ShadowList* shadowList = s->boxShadow();
1632 for (size_t i = shadowList->shadows().size(); i--; ) {
1633 const ShadowData& shadow = shadowList->shadows()[i];
1634 if (shadow.style() != shadowStyle)
1635 continue;
1636
1637 FloatSize shadowOffset(shadow.x(), shadow.y());
1638 float shadowBlur = shadow.blur();
1639 float shadowSpread = shadow.spread();
1640
1641 if (shadowOffset.isZero() && !shadowBlur && !shadowSpread)
1642 continue;
1643
1644 const Color& shadowColor = shadow.color();
1645
1646 if (shadow.style() == Normal) {
1647 FloatRect fillRect = border.rect();
1648 fillRect.inflate(shadowSpread);
1649 if (fillRect.isEmpty())
1650 continue;
1651
1652 FloatRect shadowRect(border.rect());
1653 shadowRect.inflate(shadowBlur + shadowSpread);
1654 shadowRect.move(shadowOffset);
1655
1656 // Save the state and clip, if not already done.
1657 // The clip does not depend on any shadow-specific properties.
1658 if (!stateSaver.saved()) {
1659 stateSaver.save();
1660 if (hasBorderRadius) {
1661 RoundedRect rectToClipOut = border;
1662
1663 // If the box is opaque, it is unnecessary to clip it out. H owever, doing so saves time
1664 // when painting the shadow. On the other hand, it introduce s subpixel gaps along the
1665 // corners. Those are avoided by insetting the clipping path by one pixel.
1666 if (hasOpaqueBackground)
1667 rectToClipOut.inflateWithRadii(-1);
1668
1669 if (!rectToClipOut.isEmpty()) {
1670 context->clipOutRoundedRect(rectToClipOut);
1671 }
1672 } else {
1673 // This IntRect is correct even with fractional shadows, bec ause it is used for the rectangle
1674 // of the box itself, which is always pixel-aligned.
1675 IntRect rectToClipOut = border.rect();
1676
1677 // If the box is opaque, it is unnecessary to clip it out. H owever, doing so saves time
1678 // when painting the shadow. On the other hand, it introduce s subpixel gaps along the
1679 // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path
1680 // by one pixel.
1681 if (hasOpaqueBackground) {
1682 // FIXME: The function to decide on the policy based on the transform should be a named function.
1683 // FIXME: It's not clear if this check is right. What ab out integral scale factors?
1684 // FIXME: See crbug.com/382491. The use of getCTM may al so be wrong because it does not include
1685 // device zoom applied at raster time.
1686 AffineTransform transform = context->getCTM();
1687 if (transform.a() != 1 || (transform.d() != 1 && transfo rm.d() != -1) || transform.b() || transform.c())
1688 rectToClipOut.inflate(-1);
1689 }
1690
1691 if (!rectToClipOut.isEmpty()) {
1692 context->clipOut(rectToClipOut);
1693 }
1694 }
1695 }
1696
1697 // Draw only the shadow.
1698 OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::cre ate();
1699 drawLooperBuilder->addShadow(shadowOffset, shadowBlur, shadowColor,
1700 DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder:: ShadowIgnoresAlpha);
1701 context->setDrawLooper(drawLooperBuilder.release());
1702
1703 if (hasBorderRadius) {
1704 RoundedRect influenceRect(pixelSnappedIntRect(LayoutRect(shadowR ect)), border.radii());
1705 influenceRect.expandRadii(2 * shadowBlur + shadowSpread);
1706 if (allCornersClippedOut(influenceRect, info.rect))
1707 context->fillRect(fillRect, Color::black);
1708 else {
1709 // TODO: support non-integer shadows - crbug.com/334829
1710 RoundedRect roundedFillRect = border;
1711 roundedFillRect.inflate(shadowSpread);
1712
1713 roundedFillRect.expandRadii(shadowSpread);
1714 if (!roundedFillRect.isRenderable())
1715 roundedFillRect.adjustRadii();
1716 context->fillRoundedRect(roundedFillRect, Color::black);
1717 }
1718 } else {
1719 context->fillRect(fillRect, Color::black);
1720 }
1721 } else {
1722 // The inset shadow case.
1723 GraphicsContext::Edges clippedEdges = GraphicsContext::NoEdge;
1724 if (!includeLogicalLeftEdge) {
1725 if (isHorizontal)
1726 clippedEdges |= GraphicsContext::LeftEdge;
1727 else
1728 clippedEdges |= GraphicsContext::TopEdge;
1729 }
1730 if (!includeLogicalRightEdge) {
1731 if (isHorizontal)
1732 clippedEdges |= GraphicsContext::RightEdge;
1733 else
1734 clippedEdges |= GraphicsContext::BottomEdge;
1735 }
1736 // TODO: support non-integer shadows - crbug.com/334828
1737 context->drawInnerShadow(border, shadowColor, flooredIntSize(shadowO ffset), shadowBlur, shadowSpread, clippedEdges);
1738 }
1739 }
1740 }
1741 458
1742 LayoutUnit RenderBoxModelObject::containingBlockLogicalWidthForContent() const 459 LayoutUnit RenderBoxModelObject::containingBlockLogicalWidthForContent() const
1743 { 460 {
1744 return containingBlock()->availableLogicalWidth(); 461 return containingBlock()->availableLogicalWidth();
1745 } 462 }
1746 463
1747 RenderBoxModelObject* RenderBoxModelObject::continuation() const 464 RenderBoxModelObject* RenderBoxModelObject::continuation() const
1748 { 465 {
1749 if (!continuationMap) 466 if (!continuationMap)
1750 return 0; 467 return 0;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1852 break; 569 break;
1853 } 570 }
1854 x = std::min(x, std::max<LayoutUnit>(maxX - caretWidth, 0)); 571 x = std::min(x, std::max<LayoutUnit>(maxX - caretWidth, 0));
1855 572
1856 LayoutUnit height = style()->fontMetrics().height(); 573 LayoutUnit height = style()->fontMetrics().height();
1857 LayoutUnit verticalSpace = lineHeight(true, currentStyle->isHorizontalWritin gMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes) - height; 574 LayoutUnit verticalSpace = lineHeight(true, currentStyle->isHorizontalWritin gMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes) - height;
1858 LayoutUnit y = paddingTop() + borderTop() + (verticalSpace / 2); 575 LayoutUnit y = paddingTop() + borderTop() + (verticalSpace / 2);
1859 return currentStyle->isHorizontalWritingMode() ? LayoutRect(x, y, caretWidth , height) : LayoutRect(y, x, height, caretWidth); 576 return currentStyle->isHorizontalWritingMode() ? LayoutRect(x, y, caretWidth , height) : LayoutRect(y, x, height, caretWidth);
1860 } 577 }
1861 578
1862 bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext* context)
1863 {
1864 // FIXME: We may want to not antialias when scaled by an integral value,
1865 // and we may want to antialias when translated by a non-integral value.
1866 // FIXME: See crbug.com/382491. getCTM does not include scale factors applie d at raster time, such
1867 // as device zoom.
1868 return !context->getCTM().isIdentityOrTranslationOrFlipped();
1869 }
1870
1871 void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, Tra nsformState& transformState) const 579 void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, Tra nsformState& transformState) const
1872 { 580 {
1873 RenderObject* o = container(); 581 RenderObject* o = container();
1874 if (!o) 582 if (!o)
1875 return; 583 return;
1876 584
1877 if (o->isRenderFlowThread()) 585 if (o->isRenderFlowThread())
1878 transformState.move(o->columnOffset(LayoutPoint(transformState.mappedPoi nt()))); 586 transformState.move(o->columnOffset(LayoutPoint(transformState.mappedPoi nt())));
1879 587
1880 o->mapAbsoluteToLocalPoint(mode, transformState); 588 o->mapAbsoluteToLocalPoint(mode, transformState);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1965 ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); 673 ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
1966 for (RenderObject* child = startChild; child && child != endChild; ) { 674 for (RenderObject* child = startChild; child && child != endChild; ) {
1967 // Save our next sibling as moveChildTo will clear it. 675 // Save our next sibling as moveChildTo will clear it.
1968 RenderObject* nextSibling = child->nextSibling(); 676 RenderObject* nextSibling = child->nextSibling();
1969 moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert); 677 moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert);
1970 child = nextSibling; 678 child = nextSibling;
1971 } 679 }
1972 } 680 }
1973 681
1974 } // namespace blink 682 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698