blob: 39dc7a0175937fbc4dbff0020371585502d98236 [file] [log] [blame]
// 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