Commit 10b2faf0 authored by Aaron Krajeski's avatar Aaron Krajeski Committed by Commit Bot

Change affine transforms to 4x4 transforms for canvas and path

First step on the way of getting non-affine transforms into canvas2D.
Right now this is a no-op. Trying to keep the CLs small.

CanvasRenderingContext2DState now stores a TransformationMatrix, which
is a generic 4x4 matrix instead of an AffineTransform, which is one of
those 2x3s used to encode 2D rotation/skew and a translation in the 3rd
column. For operations that require an affine transform, there's an
explicit GetAffineTransform method that constructs one.

Also, CanvasRenderingContext2DState->Transform() has become
CanvasRenderingContext2DState->GetTransform() on juanmihd@s sage advice,
which is the bulk of this change.

Bug: 1140535
Change-Id: I5630e48747dcfc7b7b27f25f1dc1a7cdd8860408
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2490821Reviewed-by: default avatarXida Chen <xidachen@chromium.org>
Reviewed-by: default avatarJuanmi Huertas <juanmihd@chromium.org>
Commit-Queue: Aaron Krajeski <aaronhk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821964}
parent 9b52a5bd
......@@ -107,13 +107,13 @@ void BaseRenderingContext2D::restore() {
return;
// Verify that the current state's transform is invertible.
if (GetState().IsTransformInvertible())
path_.Transform(GetState().Transform());
path_.Transform(GetState().GetTransform());
state_stack_.pop_back();
state_stack_.back()->ClearResolvedFilter();
if (GetState().IsTransformInvertible())
path_.Transform(GetState().Transform().Inverse());
path_.Transform(GetState().GetTransform().Inverse());
cc::PaintCanvas* c = GetOrCreatePaintCanvas();
......@@ -133,7 +133,8 @@ void BaseRenderingContext2D::RestoreMatrixClipStack(cc::PaintCanvas* c) const {
c->setMatrix(SkMatrix::I());
if (curr_state->Get()) {
curr_state->Get()->PlaybackClips(c);
c->setMatrix(AffineTransformToSkMatrix(curr_state->Get()->Transform()));
c->setMatrix(
TransformationMatrixToSkMatrix(curr_state->Get()->GetTransform()));
}
c->save();
}
......@@ -482,11 +483,11 @@ void BaseRenderingContext2D::scale(double sx, double sy) {
if (!std::isfinite(sx) || !std::isfinite(sy))
return;
AffineTransform new_transform = GetState().Transform();
TransformationMatrix new_transform = GetState().GetTransform();
float fsx = clampTo<float>(sx);
float fsy = clampTo<float>(sy);
new_transform.ScaleNonUniform(fsx, fsy);
if (GetState().Transform() == new_transform)
if (GetState().GetTransform() == new_transform)
return;
ModifiableState().SetTransform(new_transform);
......@@ -505,9 +506,9 @@ void BaseRenderingContext2D::rotate(double angle_in_radians) {
if (!std::isfinite(angle_in_radians))
return;
AffineTransform new_transform = GetState().Transform();
new_transform.RotateRadians(angle_in_radians);
if (GetState().Transform() == new_transform)
TransformationMatrix new_transform = GetState().GetTransform();
new_transform.Rotate(rad2deg(angle_in_radians));
if (GetState().GetTransform() == new_transform)
return;
ModifiableState().SetTransform(new_transform);
......@@ -527,12 +528,12 @@ void BaseRenderingContext2D::translate(double tx, double ty) {
if (!std::isfinite(tx) || !std::isfinite(ty))
return;
AffineTransform new_transform = GetState().Transform();
TransformationMatrix new_transform = GetState().GetTransform();
// clamp to float to avoid float cast overflow when used as SkScalar
float ftx = clampTo<float>(tx);
float fty = clampTo<float>(ty);
new_transform.Translate(ftx, fty);
if (GetState().Transform() == new_transform)
if (GetState().GetTransform() == new_transform)
return;
ModifiableState().SetTransform(new_transform);
......@@ -564,16 +565,16 @@ void BaseRenderingContext2D::transform(double m11,
float fdx = clampTo<float>(dx);
float fdy = clampTo<float>(dy);
AffineTransform transform(fm11, fm12, fm21, fm22, fdx, fdy);
AffineTransform new_transform = GetState().Transform() * transform;
if (GetState().Transform() == new_transform)
TransformationMatrix transform(fm11, fm12, fm21, fm22, fdx, fdy);
TransformationMatrix new_transform = GetState().GetTransform() * transform;
if (GetState().GetTransform() == new_transform)
return;
ModifiableState().SetTransform(new_transform);
if (!GetState().IsTransformInvertible())
return;
c->concat(AffineTransformToSkMatrix(transform));
c->concat(TransformationMatrixToSkMatrix(transform));
path_.Transform(transform.Inverse());
}
......@@ -582,7 +583,7 @@ void BaseRenderingContext2D::resetTransform() {
if (!c)
return;
AffineTransform ctm = GetState().Transform();
TransformationMatrix ctm = GetState().GetTransform();
bool invertible_ctm = GetState().IsTransformInvertible();
// It is possible that CTM is identity while CTM is not invertible.
// When CTM becomes non-invertible, realizeSaves() can make CTM identity.
......@@ -591,7 +592,7 @@ void BaseRenderingContext2D::resetTransform() {
// resetTransform() resolves the non-invertible CTM state.
ModifiableState().ResetTransform();
c->setMatrix(AffineTransformToSkMatrix(AffineTransform()));
c->setMatrix(TransformationMatrixToSkMatrix(TransformationMatrix()));
if (invertible_ctm)
path_.Transform(ctm);
......@@ -635,7 +636,7 @@ void BaseRenderingContext2D::setTransform(DOMMatrix2DInit* transform,
}
DOMMatrix* BaseRenderingContext2D::getTransform() {
const AffineTransform& t = GetState().Transform();
const TransformationMatrix& t = GetState().GetTransform();
DOMMatrix* m = DOMMatrix::Create();
m->setA(t.A());
m->setB(t.B());
......@@ -867,7 +868,7 @@ bool BaseRenderingContext2D::IsPointInPathInternal(
if (!std::isfinite(x) || !std::isfinite(y))
return false;
FloatPoint point(clampTo<float>(x), clampTo<float>(y));
AffineTransform ctm = GetState().Transform();
TransformationMatrix ctm = GetState().GetTransform();
FloatPoint transformed_point = ctm.Inverse().MapPoint(point);
return path.Contains(transformed_point,
......@@ -896,7 +897,7 @@ bool BaseRenderingContext2D::IsPointInStrokeInternal(const Path& path,
if (!std::isfinite(x) || !std::isfinite(y))
return false;
FloatPoint point(clampTo<float>(x), clampTo<float>(y));
AffineTransform ctm = GetState().Transform();
AffineTransform ctm = GetState().GetAffineTransform();
FloatPoint transformed_point = ctm.Inverse().MapPoint(point);
StrokeData stroke_data;
......@@ -1372,7 +1373,7 @@ bool BaseRenderingContext2D::RectContainsTransformedRect(
FloatQuad transformed_quad(
FloatRect(transformed_rect.x(), transformed_rect.y(),
transformed_rect.width(), transformed_rect.height()));
return GetState().Transform().MapQuad(quad).ContainsQuad(transformed_quad);
return GetState().GetTransform().MapQuad(quad).ContainsQuad(transformed_quad);
}
CanvasGradient* BaseRenderingContext2D::createLinearGradient(double x0,
......@@ -1528,7 +1529,7 @@ bool BaseRenderingContext2D::ComputeDirtyRect(
const FloatRect& local_rect,
const SkIRect& transformed_clip_bounds,
SkIRect* dirty_rect) {
FloatRect canvas_rect = GetState().Transform().MapRect(local_rect);
FloatRect canvas_rect = GetState().GetTransform().MapRect(local_rect);
if (AlphaChannel(GetState().ShadowColor())) {
FloatRect shadow_rect(canvas_rect);
......
......@@ -62,7 +62,7 @@ void CanvasPath::moveTo(double double_x, double double_y) {
if (!std::isfinite(x) || !std::isfinite(y))
return;
if (!IsTransformInvertible()) {
path_.MoveTo(Transform().MapPoint(FloatPoint(x, y)));
path_.MoveTo(GetTransform().MapPoint(FloatPoint(x, y)));
return;
}
path_.MoveTo(FloatPoint(x, y));
......@@ -76,7 +76,7 @@ void CanvasPath::lineTo(double double_x, double double_y) {
FloatPoint p1 = FloatPoint(x, y);
if (!IsTransformInvertible()) {
p1 = Transform().MapPoint(p1);
p1 = GetTransform().MapPoint(p1);
}
if (!path_.HasCurrentPoint())
......@@ -101,8 +101,8 @@ void CanvasPath::quadraticCurveTo(double double_cpx,
FloatPoint cp = FloatPoint(cpx, cpy);
if (!IsTransformInvertible()) {
p1 = Transform().MapPoint(p1);
cp = Transform().MapPoint(cp);
p1 = GetTransform().MapPoint(p1);
cp = GetTransform().MapPoint(cp);
}
if (!path_.HasCurrentPoint())
......@@ -132,9 +132,9 @@ void CanvasPath::bezierCurveTo(double double_cp1x,
FloatPoint cp2 = FloatPoint(cp2x, cp2y);
if (!IsTransformInvertible()) {
p1 = Transform().MapPoint(p1);
cp1 = Transform().MapPoint(cp1);
cp2 = Transform().MapPoint(cp2);
p1 = GetTransform().MapPoint(p1);
cp1 = GetTransform().MapPoint(cp1);
cp2 = GetTransform().MapPoint(cp2);
}
if (!path_.HasCurrentPoint())
path_.MoveTo(FloatPoint(cp1x, cp1y));
......@@ -168,8 +168,8 @@ void CanvasPath::arcTo(double double_x1,
FloatPoint p2 = FloatPoint(x2, y2);
if (!IsTransformInvertible()) {
p1 = Transform().MapPoint(p1);
p2 = Transform().MapPoint(p2);
p1 = GetTransform().MapPoint(p1);
p2 = GetTransform().MapPoint(p2);
}
if (!path_.HasCurrentPoint())
......
......@@ -93,8 +93,9 @@ class MODULES_EXPORT CanvasPath {
ExceptionState&);
virtual bool IsTransformInvertible() const { return true; }
virtual AffineTransform Transform() const {
return AffineTransform(1, 0, 0, 1, 0, 0);
virtual TransformationMatrix GetTransform() const {
// This will be the identity matrix
return TransformationMatrix();
}
protected:
......
......@@ -377,7 +377,7 @@ void CanvasRenderingContext2D::ScrollPathIntoViewInternal(const Path& path) {
// Apply transformation and get the bounding rect
Path transformed_path = path;
transformed_path.Transform(GetState().Transform());
transformed_path.Transform(GetState().GetAffineTransform());
FloatRect bounding_rect = transformed_path.BoundingRect();
// We first map canvas coordinates to layout coordinates.
......@@ -429,7 +429,8 @@ void CanvasRenderingContext2D::clearRect(double x,
std::isfinite(width) && std::isfinite(height)) {
FloatRect rect(clampTo<float>(x), clampTo<float>(y), clampTo<float>(width),
clampTo<float>(height));
hit_region_manager_->RemoveHitRegionsInRect(rect, GetState().Transform());
hit_region_manager_->RemoveHitRegionsInRect(
rect, GetState().GetAffineTransform());
}
}
......@@ -1058,8 +1059,8 @@ bool CanvasRenderingContext2D::IsTransformInvertible() const {
return GetState().IsTransformInvertible();
}
AffineTransform CanvasRenderingContext2D::Transform() const {
return GetState().Transform();
TransformationMatrix CanvasRenderingContext2D::GetTransform() const {
return GetState().GetTransform();
}
cc::Layer* CanvasRenderingContext2D::CcLayer() const {
......@@ -1153,7 +1154,7 @@ void CanvasRenderingContext2D::UpdateElementAccessibility(const Path& path,
// Get the transformed path.
Path transformed_path = path;
transformed_path.Transform(GetState().Transform());
transformed_path.Transform(GetState().GetAffineTransform());
// Add border and padding to the bounding rect.
LayoutRect element_rect =
......@@ -1193,7 +1194,7 @@ void CanvasRenderingContext2D::addHitRegion(const HitRegionOptions* options,
return;
}
hit_region_path.Transform(GetState().Transform());
hit_region_path.Transform(GetState().GetAffineTransform());
if (GetState().HasClip()) {
hit_region_path.IntersectPath(GetState().GetCurrentClipPath());
......
......@@ -279,7 +279,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final
void Stop() final;
bool IsTransformInvertible() const override;
AffineTransform Transform() const override;
TransformationMatrix GetTransform() const override;
cc::Layer* CcLayer() const override;
bool IsCanvas2DBufferValid() const override;
......
......@@ -39,10 +39,10 @@ CanvasRenderingContext2DState::CanvasRenderingContext2DState()
: unrealized_save_count_(0),
stroke_style_(MakeGarbageCollected<CanvasStyle>(SK_ColorBLACK)),
fill_style_(MakeGarbageCollected<CanvasStyle>(SK_ColorBLACK)),
shadow_blur_(0),
shadow_blur_(0.0),
shadow_color_(Color::kTransparent),
global_alpha_(1),
line_dash_offset_(0),
global_alpha_(1.0),
line_dash_offset_(0.0),
unparsed_font_(defaultFont),
unparsed_filter_(defaultFilter),
text_align_(kStartTextAlign),
......@@ -252,7 +252,7 @@ void CanvasRenderingContext2DState::ClipPath(
const SkPath& path,
AntiAliasingMode anti_aliasing_mode) {
clip_list_.ClipPath(path, anti_aliasing_mode,
AffineTransformToSkMatrix(transform_));
TransformationMatrixToSkMatrix(transform_));
has_clip_ = true;
if (!path.isRect(nullptr))
has_complex_clip_ = true;
......@@ -300,8 +300,15 @@ void CanvasRenderingContext2DState::SetFontVariantCaps(
SetFont(font_description, selector);
}
AffineTransform CanvasRenderingContext2DState::GetAffineTransform() const {
AffineTransform affine_transform =
AffineTransform(transform_.M11(), transform_.M12(), transform_.M21(),
transform_.M22(), transform_.M41(), transform_.M42());
return affine_transform;
}
void CanvasRenderingContext2DState::SetTransform(
const AffineTransform& transform) {
const TransformationMatrix& transform) {
is_transform_invertible_ = transform.IsInvertible();
transform_ = transform;
}
......
......@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/platform/fonts/font_selector_client.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_filter.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkRefCnt.h"
......@@ -60,10 +60,10 @@ class CanvasRenderingContext2DState final
void SetLineDashOffset(double);
double LineDashOffset() const { return line_dash_offset_; }
// setTransform returns true iff transform is invertible;
void SetTransform(const AffineTransform&);
void SetTransform(const TransformationMatrix&);
void ResetTransform();
AffineTransform Transform() const { return transform_; }
TransformationMatrix GetTransform() const { return transform_; }
AffineTransform GetAffineTransform() const;
bool IsTransformInvertible() const { return is_transform_invertible_; }
void ClipPath(const SkPath&, AntiAliasingMode);
......@@ -243,7 +243,7 @@ class CanvasRenderingContext2DState final
mutable sk_sp<PaintFilter> shadow_and_foreground_image_filter_;
double global_alpha_;
AffineTransform transform_;
TransformationMatrix transform_;
Vector<double> line_dash_;
double line_dash_offset_;
......
......@@ -128,7 +128,7 @@ void PaintRenderingContext2D::WillOverwriteCanvas() {
}
DOMMatrix* PaintRenderingContext2D::getTransform() {
const AffineTransform& t = GetState().Transform();
const TransformationMatrix& t = GetState().GetTransform();
DOMMatrix* m = DOMMatrix::Create();
m->setA(t.A() / effective_zoom_);
m->setB(t.B() / effective_zoom_);
......
......@@ -185,6 +185,10 @@ void Path::Transform(const AffineTransform& xform) {
path_.transform(AffineTransformToSkMatrix(xform));
}
void Path::Transform(const TransformationMatrix& transformation_matrix) {
path_.transform(TransformationMatrixToSkMatrix(transformation_matrix));
}
float Path::length() const {
SkScalar length = 0;
SkPathMeasure measure(path_, false);
......
......@@ -33,6 +33,7 @@
#include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
#include "third_party/blink/renderer/platform/graphics/graphics_types.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
......@@ -179,6 +180,7 @@ class PLATFORM_EXPORT Path {
void Apply(void* info, PathApplierFunction) const;
void Transform(const AffineTransform&);
void Transform(const TransformationMatrix&);
void AddPathForRoundedRect(const FloatRect&,
const FloatSize& top_left_radius,
......
......@@ -196,6 +196,10 @@ BlendMode BlendModeFromSkBlendMode(SkBlendMode blend_mode) {
}
SkMatrix AffineTransformToSkMatrix(const AffineTransform& source) {
// SkMatrices are 3x3, so they have a concept of "perspective" in the bottom
// row. blink::AffineTransform is a 2x3 matrix that can encode 2d rotations,
// skew and translation, but has no perspective. Those parameters are set to
// zero here.
SkMatrix result;
result.setScaleX(WebCoreDoubleToSkScalar(source.A()));
......@@ -206,7 +210,26 @@ SkMatrix AffineTransformToSkMatrix(const AffineTransform& source) {
result.setSkewY(WebCoreDoubleToSkScalar(source.B()));
result.setTranslateY(WebCoreDoubleToSkScalar(source.F()));
// FIXME: Set perspective properly.
result.setPerspX(0);
result.setPerspY(0);
result.set(SkMatrix::kMPersp2, SK_Scalar1);
return result;
}
SkMatrix TransformationMatrixToSkMatrix(const TransformationMatrix& source) {
// For now this just encodes to a 2x3 transform, like the above function
// TODO(aaronhk) use the perspective properly crbug.com/1140535
SkMatrix result;
result.setScaleX(WebCoreDoubleToSkScalar(source.M11()));
result.setSkewX(WebCoreDoubleToSkScalar(source.M21()));
result.setTranslateX(WebCoreDoubleToSkScalar(source.M41()));
result.setScaleY(WebCoreDoubleToSkScalar(source.M22()));
result.setSkewY(WebCoreDoubleToSkScalar(source.M12()));
result.setTranslateY(WebCoreDoubleToSkScalar(source.M42()));
result.setPerspX(0);
result.setPerspY(0);
result.set(SkMatrix::kMPersp2, SK_Scalar1);
......
......@@ -117,6 +117,8 @@ inline SkPoint FloatPointToSkPoint(const FloatPoint& point) {
}
SkMatrix PLATFORM_EXPORT AffineTransformToSkMatrix(const AffineTransform&);
SkMatrix PLATFORM_EXPORT
TransformationMatrixToSkMatrix(const TransformationMatrix&);
bool NearlyIntegral(float value);
......
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