Commit 86c8f94e authored by Fredrik Söderqvist's avatar Fredrik Söderqvist Committed by Commit Bot

Rework SVG <paint> setup

Remove the SVGPaintServer abstraction, folding it into the only
remaining user (SVGObjectPainter::PreparePaint).
LayoutSVGResourcePaintServer::PreparePaintServer() is transformed into
LayoutSVGResourcePaintServer::ApplyShader().
This provides a slimmer abstraction for <paint>s.

Bug: 109212
Change-Id: Iae577d846a61a6eae0e3689165ab616cbb70183c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2440533Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#813122}
parent 6b89e532
......@@ -44,7 +44,6 @@ blink_core_sources("svg_layout") {
"layout_svg_resource_marker.h",
"layout_svg_resource_masker.cc",
"layout_svg_resource_masker.h",
"layout_svg_resource_paint_server.cc",
"layout_svg_resource_paint_server.h",
"layout_svg_resource_pattern.cc",
"layout_svg_resource_pattern.h",
......
......@@ -25,6 +25,7 @@
#include <memory>
#include "third_party/blink/renderer/platform/graphics/gradient.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
namespace blink {
......@@ -97,22 +98,28 @@ std::unique_ptr<GradientData> LayoutSVGResourceGradient::BuildGradientData(
return gradient_data;
}
SVGPaintServer LayoutSVGResourceGradient::PreparePaintServer(
bool LayoutSVGResourceGradient::ApplyShader(
const SVGResourceClient& client,
const FloatRect& object_bounding_box) {
const FloatRect& reference_box,
const AffineTransform* additional_transform,
PaintFlags& flags) {
NOT_DESTROYED();
ClearInvalidationMask();
std::unique_ptr<GradientData>& gradient_data =
gradient_map_->insert(&client, nullptr).stored_value->value;
if (!gradient_data)
gradient_data = BuildGradientData(object_bounding_box);
gradient_data = BuildGradientData(reference_box);
if (!gradient_data->gradient)
return SVGPaintServer::Invalid();
return false;
return SVGPaintServer(gradient_data->gradient,
gradient_data->userspace_transform);
AffineTransform transform = gradient_data->userspace_transform;
if (additional_transform)
transform = *additional_transform * transform;
gradient_data->gradient->ApplyToFlags(flags,
AffineTransformToSkMatrix(transform));
return true;
}
bool LayoutSVGResourceGradient::IsChildAllowed(LayoutObject* child,
......
......@@ -39,8 +39,10 @@ class LayoutSVGResourceGradient : public LayoutSVGResourcePaintServer {
void RemoveAllClientsFromCache() final;
bool RemoveClientFromCache(SVGResourceClient&) final;
SVGPaintServer PreparePaintServer(const SVGResourceClient&,
const FloatRect& object_bounding_box) final;
bool ApplyShader(const SVGResourceClient&,
const FloatRect& reference_box,
const AffineTransform* additional_transform,
PaintFlags&) final;
bool IsChildAllowed(LayoutObject* child, const ComputedStyle&) const final;
......
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2007 Rob Buis <buis@kde.org>
* Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/skia/include/core/SkPaint.h"
namespace blink {
namespace {
// If |SVGPaintDescription::has_fallback| is true, |SVGPaintDescription::color|
// is set to a fallback color.
struct SVGPaintDescription {
STACK_ALLOCATED();
public:
SVGPaintDescription() = default;
explicit SVGPaintDescription(Color color) : color(color), is_valid(true) {}
explicit SVGPaintDescription(LayoutSVGResourcePaintServer* resource)
: resource(resource), is_valid(true) {
DCHECK(resource);
}
SVGPaintDescription(LayoutSVGResourcePaintServer* resource,
Color fallback_color)
: resource(resource),
color(fallback_color),
is_valid(true),
has_fallback(true) {
DCHECK(resource);
}
LayoutSVGResourcePaintServer* resource = nullptr;
Color color;
bool is_valid = false;
bool has_fallback = false;
};
} // namespace
SVGPaintServer::SVGPaintServer(Color color) : color_(color) {}
SVGPaintServer::SVGPaintServer(scoped_refptr<Gradient> gradient,
const AffineTransform& transform)
: gradient_(std::move(gradient)),
transform_(transform),
color_(Color::kBlack) {}
SVGPaintServer::SVGPaintServer(scoped_refptr<Pattern> pattern,
const AffineTransform& transform)
: pattern_(std::move(pattern)),
transform_(transform),
color_(Color::kBlack) {}
void SVGPaintServer::ApplyToPaintFlags(PaintFlags& flags, float alpha) {
SkColor base_color = gradient_ || pattern_ ? SK_ColorBLACK : color_.Rgb();
flags.setColor(ScaleAlpha(base_color, alpha));
if (pattern_) {
pattern_->ApplyToFlags(flags, AffineTransformToSkMatrix(transform_));
} else if (gradient_) {
gradient_->ApplyToFlags(flags, AffineTransformToSkMatrix(transform_));
} else {
flags.setShader(nullptr);
}
}
void SVGPaintServer::PrependTransform(const AffineTransform& transform) {
DCHECK(gradient_ || pattern_);
transform_ = transform * transform_;
}
static base::Optional<Color> ResolveColor(const ComputedStyle& style,
const SVGPaint& paint,
const SVGPaint& visited_paint) {
if (!paint.HasColor())
return base::nullopt;
Color color = style.ResolvedColor(paint.GetColor());
if (style.InsideLink() != EInsideLink::kInsideVisitedLink)
return color;
// FIXME: This code doesn't support the uri component of the visited link
// paint, https://bugs.webkit.org/show_bug.cgi?id=70006
if (!visited_paint.HasColor())
return color;
const Color& visited_color = style.ResolvedColor(visited_paint.GetColor());
return Color(visited_color.Red(), visited_color.Green(), visited_color.Blue(),
color.Alpha());
}
static SVGPaintDescription RequestPaint(const LayoutObject& object,
const ComputedStyle& style,
LayoutSVGResourceMode mode) {
bool apply_to_fill = mode == kApplyToFillMode;
const SVGComputedStyle& svg_style = style.SvgStyle();
const SVGPaint& paint =
apply_to_fill ? svg_style.FillPaint() : svg_style.StrokePaint();
const SVGPaint& visited_paint = apply_to_fill
? svg_style.InternalVisitedFillPaint()
: svg_style.InternalVisitedStrokePaint();
base::Optional<Color> color = ResolveColor(style, paint, visited_paint);
if (paint.HasUrl()) {
LayoutSVGResourcePaintServer* uri_resource = nullptr;
if (SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object))
uri_resource = apply_to_fill ? resources->Fill() : resources->Stroke();
if (uri_resource) {
// The paint server resource exists, though it may be invalid (pattern
// with width/height=0). Return the fallback color to our caller so it can
// use it, if PreparePaintServer() on the resource container failed.
if (color)
return SVGPaintDescription(uri_resource, *color);
return SVGPaintDescription(uri_resource);
}
// If the requested resource is not available, return the color resource or
// 'none'.
}
// Color or fallback color.
if (color)
return SVGPaintDescription(*color);
// Either 'none' or a 'none' fallback. (SVG2 say 'none' is implied when no
// fallback is specified.)
return SVGPaintDescription();
}
SVGPaintServer SVGPaintServer::RequestForLayoutObject(
const LayoutObject& layout_object,
const ComputedStyle& style,
LayoutSVGResourceMode resource_mode) {
DCHECK(resource_mode == kApplyToFillMode ||
resource_mode == kApplyToStrokeMode);
SVGPaintDescription paint_description =
RequestPaint(layout_object, style, resource_mode);
if (!paint_description.is_valid)
return Invalid();
if (!paint_description.resource)
return SVGPaintServer(paint_description.color);
SVGPaintServer paint_server = paint_description.resource->PreparePaintServer(
*SVGResources::GetClient(layout_object),
SVGResources::ReferenceBoxForEffects(layout_object));
if (paint_server.IsValid())
return paint_server;
if (paint_description.has_fallback)
return SVGPaintServer(paint_description.color);
return Invalid();
}
LayoutSVGResourcePaintServer::LayoutSVGResourcePaintServer(SVGElement* element)
: LayoutSVGResourceContainer(element) {}
LayoutSVGResourcePaintServer::~LayoutSVGResourcePaintServer() = default;
} // namespace blink
......@@ -21,59 +21,19 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_PAINT_SERVER_H_
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/gradient.h"
#include "third_party/blink/renderer/platform/graphics/pattern.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
namespace blink {
enum LayoutSVGResourceMode {
kApplyToFillMode,
kApplyToStrokeMode,
};
class LayoutObject;
class ComputedStyle;
class SVGPaintServer {
STACK_ALLOCATED();
public:
explicit SVGPaintServer(Color);
SVGPaintServer(scoped_refptr<Gradient>, const AffineTransform&);
SVGPaintServer(scoped_refptr<Pattern>, const AffineTransform&);
static SVGPaintServer RequestForLayoutObject(const LayoutObject&,
const ComputedStyle&,
LayoutSVGResourceMode);
void ApplyToPaintFlags(PaintFlags&, float alpha);
static SVGPaintServer Invalid() {
return SVGPaintServer(Color(Color::kTransparent));
}
bool IsValid() const { return color_ != Color::kTransparent; }
bool IsTransformDependent() const { return gradient_ || pattern_; }
void PrependTransform(const AffineTransform&);
private:
scoped_refptr<Gradient> gradient_;
scoped_refptr<Pattern> pattern_;
AffineTransform transform_; // Used for gradient/pattern shaders.
Color color_;
};
class LayoutSVGResourcePaintServer : public LayoutSVGResourceContainer {
public:
LayoutSVGResourcePaintServer(SVGElement*);
~LayoutSVGResourcePaintServer() override;
explicit LayoutSVGResourcePaintServer(SVGElement* element)
: LayoutSVGResourceContainer(element) {}
virtual SVGPaintServer PreparePaintServer(
const SVGResourceClient&,
const FloatRect& object_bounding_box) = 0;
virtual bool ApplyShader(const SVGResourceClient&,
const FloatRect& reference_box,
const AffineTransform* additional_transform,
PaintFlags&) = 0;
};
template <>
......
......@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
......@@ -135,21 +136,29 @@ std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
return pattern_data;
}
SVGPaintServer LayoutSVGResourcePattern::PreparePaintServer(
bool LayoutSVGResourcePattern::ApplyShader(
const SVGResourceClient& client,
const FloatRect& object_bounding_box) {
const FloatRect& reference_box,
const AffineTransform* additional_transform,
PaintFlags& flags) {
NOT_DESTROYED();
ClearInvalidationMask();
std::unique_ptr<PatternData>& pattern_data =
pattern_map_->insert(&client, nullptr).stored_value->value;
if (!pattern_data)
pattern_data = BuildPatternData(object_bounding_box);
pattern_data = BuildPatternData(reference_box);
if (!pattern_data->pattern)
return SVGPaintServer::Invalid();
return false;
return SVGPaintServer(pattern_data->pattern, pattern_data->transform);
AffineTransform transform = pattern_data->transform;
if (additional_transform)
transform = *additional_transform * transform;
pattern_data->pattern->ApplyToFlags(flags,
AffineTransformToSkMatrix(transform));
flags.setFilterQuality(kLow_SkFilterQuality);
return true;
}
const LayoutSVGResourceContainer*
......
......@@ -47,9 +47,10 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
void RemoveAllClientsFromCache() override;
bool RemoveClientFromCache(SVGResourceClient&) override;
SVGPaintServer PreparePaintServer(
const SVGResourceClient&,
const FloatRect& object_bounding_box) override;
bool ApplyShader(const SVGResourceClient&,
const FloatRect& reference_box,
const AffineTransform* additional_transform,
PaintFlags&) override;
static const LayoutSVGResourceType kResourceType = kPatternResourceType;
LayoutSVGResourceType ResourceType() const override {
......
......@@ -30,13 +30,13 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
#include "third_party/blink/renderer/core/layout/pointer_events_hit_rules.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/layout/svg/transform_helper.h"
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/svg_object_painter.h"
#include "third_party/blink/renderer/core/paint/svg_shape_painter.h"
#include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
......
......@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SVG_INLINE_TEXT_BOX_PAINTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SVG_INLINE_TEXT_BOX_PAINTER_H_
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/paint/svg_object_painter.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
......
......@@ -5,12 +5,47 @@
#include "third_party/blink/renderer/core/paint/svg_object_painter.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
namespace blink {
namespace {
Color ResolveColor(const ComputedStyle& style,
const SVGPaint& paint,
const SVGPaint& visited_paint) {
Color color = style.ResolvedColor(paint.GetColor());
if (style.InsideLink() != EInsideLink::kInsideVisitedLink)
return color;
// FIXME: This code doesn't support the uri component of the visited link
// paint, https://bugs.webkit.org/show_bug.cgi?id=70006
if (!visited_paint.HasColor())
return color;
const Color& visited_color = style.ResolvedColor(visited_paint.GetColor());
return Color(visited_color.Red(), visited_color.Green(), visited_color.Blue(),
color.Alpha());
}
void CopyStateFromGraphicsContext(GraphicsContext& context, PaintFlags& flags) {
// TODO(fs): The color filter can be set when generating a picture for a mask
// due to color-interpolation. We could also just apply the
// color-interpolation property from the the shape itself (which could mean
// the paintserver if it has it specified), since that would be more in line
// with the spec for color-interpolation. For now, just steal it from the GC
// though.
// Additionally, it's not really safe/guaranteed to be correct, as something
// down the flags pipe may want to farther tweak the color filter, which could
// yield incorrect results. (Consider just using saveLayer() w/ this color
// filter explicitly instead.)
flags.setColorFilter(sk_ref_sp(context.GetColorFilter()));
}
} // namespace
void SVGObjectPainter::PaintResourceSubtree(GraphicsContext& context) {
DCHECK(!layout_object_.NeedsLayout());
......@@ -22,6 +57,25 @@ void SVGObjectPainter::PaintResourceSubtree(GraphicsContext& context) {
layout_object_.Paint(info);
}
bool SVGObjectPainter::ApplyPaintResource(
LayoutSVGResourceMode resource_mode,
PaintFlags& flags,
const AffineTransform* additional_paint_server_transform) {
SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(layout_object_);
if (!resources)
return false;
const bool apply_to_fill = resource_mode == kApplyToFillMode;
LayoutSVGResourcePaintServer* uri_resource =
apply_to_fill ? resources->Fill() : resources->Stroke();
if (!uri_resource || !uri_resource->ApplyShader(
*SVGResources::GetClient(layout_object_),
SVGResources::ReferenceBoxForEffects(layout_object_),
additional_paint_server_transform, flags))
return false;
return true;
}
bool SVGObjectPainter::PreparePaint(
const PaintInfo& paint_info,
const ComputedStyle& style,
......@@ -36,36 +90,31 @@ bool SVGObjectPainter::PreparePaint(
return true;
}
SVGPaintServer paint_server = SVGPaintServer::RequestForLayoutObject(
layout_object_, style, resource_mode);
if (!paint_server.IsValid())
return false;
if (additional_paint_server_transform && paint_server.IsTransformDependent())
paint_server.PrependTransform(*additional_paint_server_transform);
const bool apply_to_fill = resource_mode == kApplyToFillMode;
const SVGComputedStyle& svg_style = style.SvgStyle();
float alpha = resource_mode == kApplyToFillMode ? svg_style.FillOpacity()
: svg_style.StrokeOpacity();
paint_server.ApplyToPaintFlags(flags, alpha);
// We always set filter quality to 'low' here. This value will only have an
// effect for patterns, which are SkPictures, so using high-order filter
// should have little effect on the overall quality.
flags.setFilterQuality(kLow_SkFilterQuality);
// TODO(fs): The color filter can set when generating a picture for a mask -
// due to color-interpolation. We could also just apply the
// color-interpolation property from the the shape itself (which could mean
// the paintserver if it has it specified), since that would be more in line
// with the spec for color-interpolation. For now, just steal it from the GC
// though.
// Additionally, it's not really safe/guaranteed to be correct, as
// something down the flags pipe may want to farther tweak the color
// filter, which could yield incorrect results. (Consider just using
// saveLayer() w/ this color filter explicitly instead.)
flags.setColorFilter(sk_ref_sp(paint_info.context.GetColorFilter()));
return true;
const SVGPaint& paint =
apply_to_fill ? svg_style.FillPaint() : svg_style.StrokePaint();
const float alpha =
apply_to_fill ? svg_style.FillOpacity() : svg_style.StrokeOpacity();
if (paint.HasUrl()) {
if (ApplyPaintResource(resource_mode, flags,
additional_paint_server_transform)) {
flags.setColor(ScaleAlpha(SK_ColorBLACK, alpha));
CopyStateFromGraphicsContext(paint_info.context, flags);
return true;
}
}
if (paint.HasColor()) {
const SVGPaint& visited_paint =
apply_to_fill ? svg_style.InternalVisitedFillPaint()
: svg_style.InternalVisitedStrokePaint();
const Color color = ResolveColor(style, paint, visited_paint);
flags.setColor(ScaleAlpha(color.Rgb(), alpha));
flags.setShader(nullptr);
CopyStateFromGraphicsContext(paint_info.context, flags);
return true;
}
return false;
}
} // namespace blink
......@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SVG_OBJECT_PAINTER_H_
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
namespace blink {
......@@ -16,6 +16,11 @@ class AffineTransform;
class ComputedStyle;
class GraphicsContext;
enum LayoutSVGResourceMode {
kApplyToFillMode,
kApplyToStrokeMode,
};
class SVGObjectPainter {
STACK_ALLOCATED();
......@@ -38,6 +43,11 @@ class SVGObjectPainter {
void PaintResourceSubtree(GraphicsContext&);
private:
bool ApplyPaintResource(
LayoutSVGResourceMode resource_mode,
PaintFlags& flags,
const AffineTransform* additional_paint_server_transform);
const LayoutObject& layout_object_;
};
......
......@@ -135,8 +135,7 @@ struct SVGPaint {
return type == other.type &&
(type != SVG_PAINTTYPE_COLOR || color == other.color);
}
bool HasFallbackColor() const { return type == SVG_PAINTTYPE_URI_COLOR; }
bool HasColor() const { return IsColor() || HasFallbackColor(); }
bool HasColor() const { return IsColor() || type == SVG_PAINTTYPE_URI_COLOR; }
bool HasUrl() const { return type >= SVG_PAINTTYPE_URI_NONE; }
bool HasCurrentColor() const { return HasColor() && color.IsCurrentColor(); }
StyleSVGResource* Resource() const { return resource.get(); }
......
......@@ -129,7 +129,7 @@ Canvas log:
params : {
paint : {
color : "#7F000000"
filterLevel : "Low"
filterLevel : "None"
flags : "AntiAlias"
strokeCap : "Butt"
strokeJoin : "Miter"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment