| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "core/paint/SVGImagePainter.h" |
| |
| #include "core/layout/ImageQualityController.h" |
| #include "core/layout/LayoutImageResource.h" |
| #include "core/layout/svg/LayoutSVGImage.h" |
| #include "core/paint/LayoutObjectDrawingRecorder.h" |
| #include "core/paint/ObjectPainter.h" |
| #include "core/paint/PaintInfo.h" |
| #include "core/paint/SVGPaintContext.h" |
| #include "core/svg/SVGImageElement.h" |
| #include "core/svg/graphics/SVGImage.h" |
| #include "platform/graphics/GraphicsContext.h" |
| #include "third_party/skia/include/core/SkPicture.h" |
| |
| namespace blink { |
| |
| void SVGImagePainter::paint(const PaintInfo& paintInfo) |
| { |
| if (paintInfo.phase != PaintPhaseForeground |
| || m_layoutSVGImage.style()->visibility() != EVisibility::Visible |
| || !m_layoutSVGImage.imageResource()->hasImage()) |
| return; |
| |
| FloatRect boundingBox = m_layoutSVGImage.paintInvalidationRectInLocalSVGCoordinates(); |
| if (!paintInfo.cullRect().intersectsCullRect(m_layoutSVGImage.localToSVGParentTransform(), boundingBox)) |
| return; |
| |
| PaintInfo paintInfoBeforeFiltering(paintInfo); |
| // Images cannot have children so do not call updateCullRect. |
| SVGTransformContext transformContext(paintInfoBeforeFiltering.context, m_layoutSVGImage, m_layoutSVGImage.localToSVGParentTransform()); |
| { |
| SVGPaintContext paintContext(m_layoutSVGImage, paintInfoBeforeFiltering); |
| if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintContext.paintInfo().context, m_layoutSVGImage, paintContext.paintInfo().phase)) { |
| LayoutObjectDrawingRecorder recorder(paintContext.paintInfo().context, m_layoutSVGImage, paintContext.paintInfo().phase, boundingBox); |
| paintForeground(paintContext.paintInfo()); |
| } |
| } |
| |
| if (m_layoutSVGImage.style()->outlineWidth()) { |
| PaintInfo outlinePaintInfo(paintInfoBeforeFiltering); |
| outlinePaintInfo.phase = PaintPhaseSelfOutlineOnly; |
| ObjectPainter(m_layoutSVGImage).paintOutline(outlinePaintInfo, LayoutPoint(boundingBox.location())); |
| } |
| } |
| |
| void SVGImagePainter::paintForeground(const PaintInfo& paintInfo) |
| { |
| const LayoutImageResource* imageResource = m_layoutSVGImage.imageResource(); |
| IntSize imageViewportSize = expandedIntSize(computeImageViewportSize()); |
| if (imageViewportSize.isEmpty()) |
| return; |
| |
| RefPtr<Image> image = imageResource->image(imageViewportSize, m_layoutSVGImage.style()->effectiveZoom()); |
| FloatRect destRect = m_layoutSVGImage.objectBoundingBox(); |
| FloatRect srcRect(0, 0, image->width(), image->height()); |
| |
| SVGImageElement* imageElement = toSVGImageElement(m_layoutSVGImage.element()); |
| imageElement->preserveAspectRatio()->currentValue()->transformRect(destRect, srcRect); |
| |
| InterpolationQuality interpolationQuality = InterpolationDefault; |
| interpolationQuality = ImageQualityController::imageQualityController()->chooseInterpolationQuality(m_layoutSVGImage, image.get(), image.get(), LayoutSize(destRect.size())); |
| |
| InterpolationQuality previousInterpolationQuality = paintInfo.context.imageInterpolationQuality(); |
| paintInfo.context.setImageInterpolationQuality(interpolationQuality); |
| paintInfo.context.drawImage(image.get(), destRect, &srcRect); |
| paintInfo.context.setImageInterpolationQuality(previousInterpolationQuality); |
| } |
| |
| FloatSize SVGImagePainter::computeImageViewportSize() const |
| { |
| ASSERT(m_layoutSVGImage.imageResource()->hasImage()); |
| |
| if (toSVGImageElement(m_layoutSVGImage.element())->preserveAspectRatio()->currentValue()->align() != SVGPreserveAspectRatio::kSvgPreserveaspectratioNone) |
| return m_layoutSVGImage.objectBoundingBox().size(); |
| |
| ImageResource* cachedImage = m_layoutSVGImage.imageResource()->cachedImage(); |
| |
| // Images with preserveAspectRatio=none should force non-uniform scaling. This can be achieved |
| // by setting the image's container size to its viewport size (i.e. concrete object size |
| // returned by the default sizing algorithm.) See |
| // https://www.w3.org/TR/SVG/single-page.html#coords-PreserveAspectRatioAttribute and |
| // https://drafts.csswg.org/css-images-3/#default-sizing. |
| |
| // Avoid returning the size of the broken image. |
| if (cachedImage->errorOccurred()) |
| return FloatSize(); |
| |
| if (cachedImage->getImage()->isSVGImage()) |
| return toSVGImage(cachedImage->getImage())->concreteObjectSize(m_layoutSVGImage.objectBoundingBox().size()); |
| |
| return FloatSize(cachedImage->getImage()->size()); |
| } |
| |
| } // namespace blink |