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

Side by Side Diff: Source/core/paint/BoxPainter.cpp

Issue 1300103003: Refactor code for calculating background image geometry (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 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
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/BoxPainter.h" 6 #include "core/paint/BoxPainter.h"
7 7
8 #include "core/HTMLNames.h" 8 #include "core/HTMLNames.h"
9 #include "core/frame/Settings.h" 9 #include "core/frame/Settings.h"
10 #include "core/html/HTMLFrameOwnerElement.h" 10 #include "core/html/HTMLFrameOwnerElement.h"
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 } 433 }
434 case BorderFillBox: 434 case BorderFillBox:
435 break; 435 break;
436 default: 436 default:
437 ASSERT_NOT_REACHED(); 437 ASSERT_NOT_REACHED();
438 break; 438 break;
439 } 439 }
440 440
441 BackgroundImageGeometry geometry; 441 BackgroundImageGeometry geometry;
442 if (bgImage) 442 if (bgImage)
443 calculateBackgroundImageGeometry(obj, paintInfo.paintContainer(), paintI nfo.globalPaintFlags(), bgLayer, scrolledPaintRect, geometry, backgroundObject); 443 geometry.calculate(obj, paintInfo.paintContainer(), paintInfo.globalPain tFlags(), bgLayer, scrolledPaintRect, backgroundObject);
444 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(obj, obj.sty le()->effectiveZoom()); 444 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(obj, obj.sty le()->effectiveZoom());
445 445
446 // Paint the color first underneath all images, culled if background image o ccludes it. 446 // Paint the color first underneath all images, culled if background image o ccludes it.
447 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the cu lling test 447 // TODO(trchen): In the !bgLayer.hasRepeatXY() case, we could improve the cu lling test
448 // by verifying whether the background image covers the entire painting area . 448 // by verifying whether the background image covers the entire painting area .
449 if (isBottomLayer) { 449 if (isBottomLayer) {
450 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); 450 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect));
451 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box); 451 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box);
452 bool backgroundImageOccludesBackgroundColor = shouldPaintBackgroundImage && isFillLayerOpaque(bgLayer, obj); 452 bool backgroundImageOccludesBackgroundColor = shouldPaintBackgroundImage && isFillLayerOpaque(bgLayer, obj);
453 if (boxShadowShouldBeAppliedToBackground || !backgroundImageOccludesBack groundColor) { 453 if (boxShadowShouldBeAppliedToBackground || !backgroundImageOccludesBack groundColor) {
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 return; 563 return;
564 564
565 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte xt, m_layoutBox, paintInfo.phase)) 565 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.conte xt, m_layoutBox, paintInfo.phase))
566 return; 566 return;
567 567
568 IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset, m_layoutBox. size())); 568 IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset, m_layoutBox. size()));
569 LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutBox, paintInfo.phase, paintRect); 569 LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutBox, paintInfo.phase, paintRect);
570 paintInfo.context->fillRect(paintRect, Color::black); 570 paintInfo.context->fillRect(paintRect, Color::black);
571 } 571 }
572 572
573 // Return the amount of space to leave between image tiles for the background-re peat: space property.
574 static inline int getSpaceBetweenImageTiles(int areaSize, int tileSize)
575 {
576 int numberOfTiles = areaSize / tileSize;
577 int space = -1;
578
579 if (numberOfTiles > 1) {
580 // Spec doesn't specify rounding, so use the same method as for backgrou nd-repeat: round.
581 space = lroundf((areaSize - numberOfTiles * tileSize) / (float)(numberOf Tiles - 1));
582 }
583
584 return space;
585 }
586
587 void BoxPainter::calculateBackgroundImageGeometry(const LayoutBoxModelObject& ob j, const LayoutBoxModelObject* paintContainer, const GlobalPaintFlags globalPain tFlags, const FillLayer& fillLayer, const LayoutRect& paintRect,
588 BackgroundImageGeometry& geometry, LayoutObject* backgroundObject)
589 {
590 LayoutUnit left = 0;
591 LayoutUnit top = 0;
592 IntSize positioningAreaSize;
593 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
594 bool isLayoutView = obj.isLayoutView();
595 const LayoutBox* rootBox = nullptr;
596 if (isLayoutView) {
597 // It is only possible reach here when root element has a box.
598 Element* documentElement = obj.document().documentElement();
599 ASSERT(documentElement);
600 ASSERT(documentElement->layoutObject());
601 ASSERT(documentElement->layoutObject()->isBox());
602 rootBox = toLayoutBox(documentElement->layoutObject());
603 }
604 const LayoutBoxModelObject& positioningBox = isLayoutView ? static_cast<cons t LayoutBoxModelObject&>(*rootBox) : obj;
605
606 // Determine the background positioning area and set destRect to the backgro und painting area.
607 // destRect will be adjusted later if the background is non-repeating.
608 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins ide transforms.
609 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment;
610
611 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
612 // As a side effect of an optimization to blit on scroll, we do not hono r the CSS
613 // property "background-attachment: fixed" because it may result in rend ering
614 // artifacts. Note, these artifacts only appear if we are blitting on sc roll of
615 // a page that has fixed background images.
616 fixedAttachment = false;
617 }
618
619 if (!fixedAttachment) {
620 geometry.setDestRect(snappedPaintRect);
621
622 LayoutUnit right = 0;
623 LayoutUnit bottom = 0;
624 // Scroll and Local.
625 if (fillLayer.origin() != BorderFillBox) {
626 left = positioningBox.borderLeft();
627 right = positioningBox.borderRight();
628 top = positioningBox.borderTop();
629 bottom = positioningBox.borderBottom();
630 if (fillLayer.origin() == ContentFillBox) {
631 left += positioningBox.paddingLeft();
632 right += positioningBox.paddingRight();
633 top += positioningBox.paddingTop();
634 bottom += positioningBox.paddingBottom();
635 }
636 }
637
638 if (isLayoutView) {
639 // The background of the box generated by the root element covers th e entire canvas and will
640 // be painted by the view object, but the we should still use the ro ot element box for
641 // positioning.
642 positioningAreaSize = pixelSnappedIntSize(rootBox->size() - LayoutSi ze(left + right, top + bottom), rootBox->location());
643 // The input paint rect is specified in root element local coordinat e (i.e. a transform
644 // is applied on the context for painting), and is expanded to cover the whole canvas.
645 // Since left/top is relative to the paint rect, we need to offset t hem back.
646 left -= paintRect.x();
647 top -= paintRect.y();
648 } else {
649 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS ize(left + right, top + bottom), paintRect.location());
650 }
651 } else {
652 geometry.setHasNonLocalGeometry();
653
654 IntRect viewportRect = pixelSnappedIntRect(obj.viewRect());
655 if (fixedBackgroundPaintsInLocalCoordinates(obj, globalPaintFlags))
656 viewportRect.setLocation(IntPoint());
657 else if (FrameView* frameView = obj.view()->frameView())
658 viewportRect.setLocation(frameView->scrollPosition());
659
660 if (paintContainer) {
661 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l ocalToAbsolute(FloatPoint()));
662 viewportRect.moveBy(-absoluteContainerOffset);
663 }
664
665 geometry.setDestRect(viewportRect);
666 positioningAreaSize = geometry.destRect().size();
667 }
668
669 const LayoutObject* clientForBackgroundImage = backgroundObject ? background Object : &obj;
670 IntSize fillTileSize = calculateFillTileSize(positioningBox, fillLayer, posi tioningAreaSize);
671 fillLayer.image()->setContainerSizeForLayoutObject(clientForBackgroundImage, fillTileSize, obj.style()->effectiveZoom());
672 geometry.setTileSize(fillTileSize);
673
674 EFillRepeat backgroundRepeatX = fillLayer.repeatX();
675 EFillRepeat backgroundRepeatY = fillLayer.repeatY();
676 int availableWidth = positioningAreaSize.width() - geometry.tileSize().width ();
677 int availableHeight = positioningAreaSize.height() - geometry.tileSize().hei ght();
678
679 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit ion(), availableWidth);
680 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil lTileSize.width() > 0) {
681 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.width() / fillTileSize.width()));
682
683 // Round tile size per css3-background spec.
684 fillTileSize.setWidth(lroundf(positioningAreaSize.width() / (float)nrTil es));
685
686 // Maintain aspect ratio if background-size: auto is set
687 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun dFill) {
688 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w idth() / (nrTiles * fillTileSize.width()));
689 }
690
691 geometry.setTileSize(fillTileSize);
692 geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().wid th() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
693 geometry.setSpaceSize(IntSize());
694 }
695
696 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit ion(), availableHeight);
697 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fi llTileSize.height() > 0) {
698 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.height() / fillTileSize.height()));
699
700 // Round tile size per css3-background spec.
701 fillTileSize.setHeight(lroundf(positioningAreaSize.height() / (float)nrT iles));
702
703 // Maintain aspect ratio if background-size: auto is set
704 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round Fill) {
705 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei ght() / (nrTiles * fillTileSize.height()));
706 }
707
708 geometry.setTileSize(fillTileSize);
709 geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().he ight() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0) ;
710 geometry.setSpaceSize(IntSize());
711 }
712
713 if (backgroundRepeatX == RepeatFill) {
714 int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidt h - computedXPosition : computedXPosition;
715 geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().wid th() - roundToInt(xOffset + left) % geometry.tileSize().width() : 0);
716 geometry.setSpaceSize(IntSize());
717 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
718 int space = getSpaceBetweenImageTiles(positioningAreaSize.width(), geome try.tileSize().width());
719 int actualWidth = geometry.tileSize().width() + space;
720
721 if (space >= 0) {
722 computedXPosition = roundedMinimumValueForLength(Length(), available Width);
723 geometry.setSpaceSize(IntSize(space, 0));
724 geometry.setPhaseX(actualWidth ? actualWidth - roundToInt(computedXP osition + left) % actualWidth : 0);
725 } else {
726 backgroundRepeatX = NoRepeatFill;
727 }
728 }
729 if (backgroundRepeatX == NoRepeatFill) {
730 int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidt h - computedXPosition : computedXPosition;
731 geometry.setNoRepeatX(left + xOffset);
732 geometry.setSpaceSize(IntSize(0, geometry.spaceSize().height()));
733 }
734
735 if (backgroundRepeatY == RepeatFill) {
736 int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHei ght - computedYPosition : computedYPosition;
737 geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().he ight() - roundToInt(yOffset + top) % geometry.tileSize().height() : 0);
738 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
739 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
740 int space = getSpaceBetweenImageTiles(positioningAreaSize.height(), geom etry.tileSize().height());
741 int actualHeight = geometry.tileSize().height() + space;
742
743 if (space >= 0) {
744 computedYPosition = roundedMinimumValueForLength(Length(), available Height);
745 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), space));
746 geometry.setPhaseY(actualHeight ? actualHeight - roundToInt(computed YPosition + top) % actualHeight : 0);
747 } else {
748 backgroundRepeatY = NoRepeatFill;
749 }
750 }
751 if (backgroundRepeatY == NoRepeatFill) {
752 int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHei ght - computedYPosition : computedYPosition;
753 geometry.setNoRepeatY(top + yOffset);
754 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
755 }
756
757 if (fixedAttachment)
758 geometry.useFixedAttachment(snappedPaintRect.location());
759
760 geometry.clip(snappedPaintRect);
761 }
762
763 InterpolationQuality BoxPainter::chooseInterpolationQuality(LayoutObject& obj, G raphicsContext* context, Image* image, const void* layer, const LayoutSize& size ) 573 InterpolationQuality BoxPainter::chooseInterpolationQuality(LayoutObject& obj, G raphicsContext* context, Image* image, const void* layer, const LayoutSize& size )
764 { 574 {
765 return ImageQualityController::imageQualityController()->chooseInterpolation Quality(context, &obj, image, layer, size); 575 return ImageQualityController::imageQualityController()->chooseInterpolation Quality(context, &obj, image, layer, size);
766 } 576 }
767 577
768 bool BoxPainter::fixedBackgroundPaintsInLocalCoordinates(const LayoutObject& obj , const GlobalPaintFlags globalPaintFlags)
769 {
770 if (!obj.isLayoutView())
771 return false;
772
773 const LayoutView& view = toLayoutView(obj);
774
775 if (globalPaintFlags & GlobalPaintFlattenCompositingLayers)
776 return false;
777
778 DeprecatedPaintLayer* rootLayer = view.layer();
779 if (!rootLayer || rootLayer->compositingState() == NotComposited)
780 return false;
781
782 return rootLayer->compositedDeprecatedPaintLayerMapping()->backgroundLayerPa intsFixedRootBackground();
783 }
784
785 static inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSize& positioningAreaSize)
786 {
787 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile Size.width().ceil() : tileSize.width().floor());
788 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t ileSize.height().ceil() : tileSize.height().floor());
789 }
790
791 IntSize BoxPainter::calculateFillTileSize(const LayoutBoxModelObject& obj, const FillLayer& fillLayer, const IntSize& positioningAreaSize)
792 {
793 StyleImage* image = fillLayer.image();
794 EFillSizeType type = fillLayer.size().type;
795
796 IntSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, po sitioningAreaSize, LayoutBoxModelObject::ScaleByEffectiveZoom);
797 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal eFactor());
798 switch (type) {
799 case SizeLength: {
800 LayoutSize tileSize(positioningAreaSize);
801
802 Length layerWidth = fillLayer.size().size.width();
803 Length layerHeight = fillLayer.size().size.height();
804
805 if (layerWidth.isFixed())
806 tileSize.setWidth(layerWidth.value());
807 else if (layerWidth.hasPercent())
808 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid th()));
809
810 if (layerHeight.isFixed())
811 tileSize.setHeight(layerHeight.value());
812 else if (layerHeight.hasPercent())
813 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h eight()));
814
815 applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize);
816
817 // If one of the values is auto we have to use the appropriate
818 // scale to maintain our aspect ratio.
819 if (layerWidth.isAuto() && !layerHeight.isAuto()) {
820 if (imageIntrinsicSize.height()) {
821 LayoutUnit adjustedWidth = imageIntrinsicSize.width() * tileSize .height() / imageIntrinsicSize.height();
822 if (imageIntrinsicSize.width() >= 1 && adjustedWidth < 1)
823 adjustedWidth = 1;
824 tileSize.setWidth(adjustedWidth);
825 }
826 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
827 if (imageIntrinsicSize.width()) {
828 LayoutUnit adjustedHeight = imageIntrinsicSize.height() * tileSi ze.width() / imageIntrinsicSize.width();
829 if (imageIntrinsicSize.height() >= 1 && adjustedHeight < 1)
830 adjustedHeight = 1;
831 tileSize.setHeight(adjustedHeight);
832 }
833 } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
834 // If both width and height are auto, use the image's intrinsic size .
835 tileSize = LayoutSize(imageIntrinsicSize);
836 }
837
838 tileSize.clampNegativeToZero();
839 return flooredIntSize(tileSize);
840 }
841 case SizeNone: {
842 // If both values are 'auto' then the intrinsic width and/or height of t he image should be used, if any.
843 if (!imageIntrinsicSize.isEmpty())
844 return imageIntrinsicSize;
845
846 // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
847 type = Contain;
848 }
849 case Contain:
850 case Cover: {
851 float horizontalScaleFactor = imageIntrinsicSize.width()
852 ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSi ze.width() : 1;
853 float verticalScaleFactor = imageIntrinsicSize.height()
854 ? static_cast<float>(positioningAreaSize.height()) / imageIntrinsicS ize.height() : 1;
855 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor);
856 return IntSize(std::max(1l, lround(imageIntrinsicSize.width() * scaleFac tor)), std::max(1l, lround(imageIntrinsicSize.height() * scaleFactor)));
857 }
858 }
859
860 ASSERT_NOT_REACHED();
861 return IntSize();
862 }
863
864 bool BoxPainter::paintNinePieceImage(LayoutBoxModelObject& obj, GraphicsContext* graphicsContext, const LayoutRect& rect, const ComputedStyle& style, const Nine PieceImage& ninePieceImage, SkXfermode::Mode op) 578 bool BoxPainter::paintNinePieceImage(LayoutBoxModelObject& obj, GraphicsContext* graphicsContext, const LayoutRect& rect, const ComputedStyle& style, const Nine PieceImage& ninePieceImage, SkXfermode::Mode op)
865 { 579 {
866 NinePieceImagePainter ninePieceImagePainter(obj); 580 NinePieceImagePainter ninePieceImagePainter(obj);
867 return ninePieceImagePainter.paint(graphicsContext, rect, style, ninePieceIm age, op); 581 return ninePieceImagePainter.paint(graphicsContext, rect, style, ninePieceIm age, op);
868 } 582 }
869 583
870 bool BoxPainter::shouldAntialiasLines(GraphicsContext* context) 584 bool BoxPainter::shouldAntialiasLines(GraphicsContext* context)
871 { 585 {
872 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) 586 if (RuntimeEnabledFeatures::slimmingPaintEnabled())
873 return true; 587 return true;
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 } 760 }
1047 } 761 }
1048 762
1049 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(const ComputedStyle& style, const Document& document) 763 bool BoxPainter::shouldForceWhiteBackgroundForPrintEconomy(const ComputedStyle& style, const Document& document)
1050 { 764 {
1051 return document.printing() && style.printColorAdjust() == PrintColorAdjustEc onomy 765 return document.printing() && style.printColorAdjust() == PrintColorAdjustEc onomy
1052 && (!document.settings() || !document.settings()->shouldPrintBackgrounds ()); 766 && (!document.settings() || !document.settings()->shouldPrintBackgrounds ());
1053 } 767 }
1054 768
1055 } // namespace blink 769 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/paint/BoxPainter.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698