diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/canvas')
33 files changed, 2094 insertions, 394 deletions
diff --git a/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn b/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn index 3dee2798eee..2a069bf9356 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn +++ b/chromium/third_party/blink/renderer/modules/canvas/BUILD.gn @@ -9,8 +9,14 @@ blink_modules_sources("canvas") { sources = [ "canvas2d/base_rendering_context_2d.cc", "canvas2d/base_rendering_context_2d.h", + "canvas2d/canvas_formatted_text.cc", + "canvas2d/canvas_formatted_text.h", + "canvas2d/canvas_formatted_text_run.cc", + "canvas2d/canvas_formatted_text_run.h", "canvas2d/canvas_gradient.cc", "canvas2d/canvas_gradient.h", + "canvas2d/canvas_image_source_util.cc", + "canvas2d/canvas_image_source_util.h", "canvas2d/canvas_path.cc", "canvas2d/canvas_path.h", "canvas2d/canvas_pattern.cc", @@ -32,15 +38,22 @@ blink_modules_sources("canvas") { "htmlcanvas/canvas_context_creation_attributes_helpers.h", "htmlcanvas/html_canvas_element_module.cc", "htmlcanvas/html_canvas_element_module.h", + "imagebitmap/image_bitmap_factories.cc", + "imagebitmap/image_bitmap_factories.h", "imagebitmap/image_bitmap_rendering_context.cc", "imagebitmap/image_bitmap_rendering_context.h", "imagebitmap/image_bitmap_rendering_context_base.cc", "imagebitmap/image_bitmap_rendering_context_base.h", + "imagebitmap/image_bitmap_source_union.h", "offscreencanvas/offscreen_canvas_module.cc", "offscreencanvas/offscreen_canvas_module.h", "offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc", "offscreencanvas2d/offscreen_canvas_rendering_context_2d.h", ] + + deps = [ "//third_party/blink/renderer/modules/webcodecs" ] + allow_circular_includes_from = + [ "//third_party/blink/renderer/modules/webcodecs" ] } fuzzer_test("canvas_fuzzer") { diff --git a/chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA b/chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA new file mode 100644 index 00000000000..73333465b1f --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/DIR_METADATA @@ -0,0 +1,4 @@ +monorail { + component: "Blink>Canvas" +} +team_email: "paint-dev@chromium.org"
\ No newline at end of file diff --git a/chromium/third_party/blink/renderer/modules/canvas/OWNERS b/chromium/third_party/blink/renderer/modules/canvas/OWNERS index 4abe99a57af..319149318fa 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/OWNERS +++ b/chromium/third_party/blink/renderer/modules/canvas/OWNERS @@ -6,6 +6,3 @@ yiyix@chromium.org senorblanco@chromium.org # lowLatency mcasas@chromium.org - -# TEAM: paint-dev@chromium.org -# COMPONENT: Blink>Canvas diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc index efc376143b4..98b485c0911 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc @@ -12,13 +12,9 @@ #include "base/metrics/histogram_functions.h" #include "base/numerics/checked_math.h" #include "third_party/blink/public/common/features.h" -#include "third_party/blink/renderer/core/css/cssom/css_url_image_value.h" #include "third_party/blink/renderer/core/css/parser/css_parser.h" #include "third_party/blink/renderer/core/html/canvas/text_metrics.h" -#include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" -#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" -#include "third_party/blink/renderer/core/svg/svg_image_element.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_pattern.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/path_2d.h" #include "third_party/blink/renderer/platform/geometry/float_quad.h" @@ -36,6 +32,15 @@ const char BaseRenderingContext2D::kLtrDirectionString[] = "ltr"; const char BaseRenderingContext2D::kAutoKerningString[] = "auto"; const char BaseRenderingContext2D::kNormalKerningString[] = "normal"; const char BaseRenderingContext2D::kNoneKerningString[] = "none"; +const char BaseRenderingContext2D::kUltraCondensedString[] = "ultra-condensed"; +const char BaseRenderingContext2D::kExtraCondensedString[] = "extra-condensed"; +const char BaseRenderingContext2D::kCondensedString[] = "condensed"; +const char BaseRenderingContext2D::kSemiCondensedString[] = "semi-condensed"; +const char BaseRenderingContext2D::kNormalStretchString[] = "normal"; +const char BaseRenderingContext2D::kSemiExpandedString[] = "semi-expanded"; +const char BaseRenderingContext2D::kExpandedString[] = "expanded"; +const char BaseRenderingContext2D::kExtraExpandedString[] = "extra-expanded"; +const char BaseRenderingContext2D::kUltraExpandedString[] = "ultra-expanded"; const char BaseRenderingContext2D::kNormalVariantString[] = "normal"; const char BaseRenderingContext2D::kSmallCapsVariantString[] = "small-caps"; const char BaseRenderingContext2D::kAllSmallCapsVariantString[] = @@ -136,11 +141,11 @@ void BaseRenderingContext2D::RestoreMatrixClipStack(cc::PaintCanvas* c) const { DCHECK(state_stack_.begin() < state_stack_.end()); for (curr_state = state_stack_.begin(); curr_state < state_stack_.end(); curr_state++) { - c->setMatrix(SkMatrix::I()); + c->setMatrix(SkM44()); if (curr_state->Get()) { curr_state->Get()->PlaybackClips(c); c->setMatrix( - TransformationMatrixToSkMatrix(curr_state->Get()->GetTransform())); + TransformationMatrix::ToSkM44(curr_state->Get()->GetTransform())); } c->save(); } @@ -175,6 +180,9 @@ void BaseRenderingContext2D::reset() { DCHECK(c->getDeviceClipBounds(&clip_bounds)); DCHECK(clip_bounds == c->imageInfo().bounds()); #endif + // We only want to clear the backing buffer if the surface exists because + // this function is also used when the context is lost. + clearRect(0, 0, Width(), Height()); } ValidateStateStack(); origin_tainted_by_content_ = false; @@ -208,6 +216,15 @@ void BaseRenderingContext2D::IdentifiabilityMaybeUpdateForStyleUnion( } } +RespectImageOrientationEnum +BaseRenderingContext2D::RespectImageOrientationInternal( + CanvasImageSource* image_source) { + if ((image_source->IsImageBitmap() || image_source->IsImageElement()) && + image_source->WouldTaintOrigin()) + return kRespectImageOrientation; + return RespectImageOrientation(); +} + void BaseRenderingContext2D::strokeStyle( StringOrCanvasGradientOrCanvasPattern& return_value) const { ConvertCanvasStyleToUnionType(GetState().StrokeStyle(), return_value); @@ -474,6 +491,8 @@ void BaseRenderingContext2D::setFilter( } void BaseRenderingContext2D::scale(double sx, double sy) { + // TODO(crbug.com/1140535): Investigate the performance impact of simply + // calling the 3d version of this function cc::PaintCanvas* c = GetOrCreatePaintCanvas(); if (!c) return; @@ -496,6 +515,33 @@ void BaseRenderingContext2D::scale(double sx, double sy) { path_.Transform(AffineTransform().ScaleNonUniform(1.0 / fsx, 1.0 / fsy)); } +void BaseRenderingContext2D::scale(double sx, double sy, double sz) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (!std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sz)) + return; + + TransformationMatrix new_transform = GetState().GetTransform(); + float fsx = clampTo<float>(sx); + float fsy = clampTo<float>(sy); + float fsz = clampTo<float>(sz); + new_transform.Scale3d(fsx, fsy, fsz); + if (GetState().GetTransform() == new_transform) + return; + + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + // SkCanvas has no 3d scale method for now + TransformationMatrix scale_matrix = + TransformationMatrix().Scale3d(fsx, fsy, fsz); + c->concat(TransformationMatrix::ToSkM44(scale_matrix)); + path_.Transform(scale_matrix); +} + void BaseRenderingContext2D::rotate(double angle_in_radians) { cc::PaintCanvas* c = GetOrCreatePaintCanvas(); if (!c) @@ -516,10 +562,70 @@ void BaseRenderingContext2D::rotate(double angle_in_radians) { path_.Transform(AffineTransform().RotateRadians(-angle_in_radians)); } +// All angles are in radians +void BaseRenderingContext2D::rotate3d(double rx, double ry, double rz) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (!std::isfinite(rx) || !std::isfinite(ry) || !std::isfinite(rz)) + return; + + TransformationMatrix rotation_matrix = + TransformationMatrix().Rotate3d(rad2deg(rx), rad2deg(ry), rad2deg(rz)); + + // Check if the transformation is a no-op and early out if that is the case. + TransformationMatrix new_transform = + GetState().GetTransform().Rotate3d(rad2deg(rx), rad2deg(ry), rad2deg(rz)); + if (GetState().GetTransform() == new_transform) + return; + + // Must call setTransform to set the IsTransformInvertible flag. + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + c->concat(TransformationMatrix::ToSkM44(rotation_matrix)); + path_.Transform(rotation_matrix.Inverse()); +} + +void BaseRenderingContext2D::rotateAxis(double axisX, + double axisY, + double axisZ, + double angle_in_radians) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (!std::isfinite(axisX) || !std::isfinite(axisY) || !std::isfinite(axisZ) || + !std::isfinite(angle_in_radians)) + return; + + TransformationMatrix rotation_matrix = TransformationMatrix().Rotate3d( + axisX, axisY, axisZ, rad2deg(angle_in_radians)); + + // Check if the transformation is a no-op and early out if that is the case. + TransformationMatrix new_transform = GetState().GetTransform().Rotate3d( + axisX, axisY, axisZ, rad2deg(angle_in_radians)); + if (GetState().GetTransform() == new_transform) + return; + + // Must call setTransform to set the IsTransformInvertible flag. + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + c->concat(TransformationMatrix::ToSkM44(rotation_matrix)); + path_.Transform(rotation_matrix.Inverse()); +} + void BaseRenderingContext2D::translate(double tx, double ty) { + // TODO(crbug.com/1140535): Investigate the performance impact of simply + // calling the 3d version of this function cc::PaintCanvas* c = GetOrCreatePaintCanvas(); if (!c) return; + if (!GetState().IsTransformInvertible()) return; @@ -537,16 +643,144 @@ void BaseRenderingContext2D::translate(double tx, double ty) { ModifiableState().SetTransform(new_transform); if (!GetState().IsTransformInvertible()) return; + c->translate(ftx, fty); path_.Transform(AffineTransform().Translate(-ftx, -fty)); } +void BaseRenderingContext2D::translate(double tx, double ty, double tz) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (!std::isfinite(tx) || !std::isfinite(ty) || !std::isfinite(tz)) + return; + + // clamp to float to avoid float cast overflow when used as SkScalar + float ftx = clampTo<float>(tx); + float fty = clampTo<float>(ty); + float ftz = clampTo<float>(ty); + + TransformationMatrix translation_matrix = + TransformationMatrix().Translate3d(ftx, fty, ftz); + + // Check if the transformation is a no-op and early out if that is the case. + TransformationMatrix new_transform = + GetState().GetTransform().Translate3d(ftx, fty, ftz); + if (GetState().GetTransform() == new_transform) + return; + + // We need to call SetTransform() to set the IsTransformInvertible flag. + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + c->concat(TransformationMatrix::ToSkM44(translation_matrix)); + path_.Transform(translation_matrix.Inverse()); +} + +void BaseRenderingContext2D::perspective(double length) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (length == 0 || !std::isfinite(length)) + return; + + float flength = clampTo<float>(length); + + TransformationMatrix perspective_matrix = + TransformationMatrix().ApplyPerspective(flength); + + // Check if the transformation is a no-op and early out if that is the case. + TransformationMatrix new_transform = + GetState().GetTransform().ApplyPerspective(flength); + if (GetState().GetTransform() == new_transform) + return; + + // We need to call SetTransform() to set the IsTransformInvertible flag. + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + c->concat(TransformationMatrix::ToSkM44(perspective_matrix)); + path_.Transform(perspective_matrix.Inverse()); +} + +void BaseRenderingContext2D::transform(double m11, + double m12, + double m13, + double m14, + double m21, + double m22, + double m23, + double m24, + double m31, + double m32, + double m33, + double m34, + double m41, + double m42, + double m43, + double m44) { + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); + if (!c) + return; + + if (!std::isfinite(m11) || !std::isfinite(m12) || !std::isfinite(m13) || + !std::isfinite(m14) || !std::isfinite(m21) || !std::isfinite(m22) || + !std::isfinite(m23) || !std::isfinite(m24) || !std::isfinite(m31) || + !std::isfinite(m32) || !std::isfinite(m33) || !std::isfinite(m34) || + !std::isfinite(m41) || !std::isfinite(m42) || !std::isfinite(m43) || + !std::isfinite(m44)) + return; + + // clamp to float to avoid float cast overflow when used as SkScalar + float fm11 = clampTo<float>(m11); + float fm12 = clampTo<float>(m12); + float fm13 = clampTo<float>(m13); + float fm14 = clampTo<float>(m14); + float fm21 = clampTo<float>(m21); + float fm22 = clampTo<float>(m22); + float fm23 = clampTo<float>(m23); + float fm24 = clampTo<float>(m24); + float fm31 = clampTo<float>(m31); + float fm32 = clampTo<float>(m32); + float fm33 = clampTo<float>(m33); + float fm34 = clampTo<float>(m34); + float fm41 = clampTo<float>(m41); + float fm42 = clampTo<float>(m42); + float fm43 = clampTo<float>(m43); + float fm44 = clampTo<float>(m44); + + TransformationMatrix transform = + TransformationMatrix(fm11, fm12, fm13, fm14, fm21, fm22, fm23, fm24, fm31, + fm32, fm33, fm34, fm41, fm42, fm43, fm44); + + // Check if the transformation is a no-op and early out if that is the case. + TransformationMatrix new_transform = GetState().GetTransform() * transform; + if (GetState().GetTransform() == new_transform) + return; + + // Must call setTransform to set the IsTransformInvertible flag. + ModifiableState().SetTransform(new_transform); + if (!GetState().IsTransformInvertible()) + return; + + c->concat(TransformationMatrix::ToSkM44(transform)); + path_.Transform(transform.Inverse()); +} + void BaseRenderingContext2D::transform(double m11, double m12, double m21, double m22, double dx, double dy) { + // TODO(crbug.com/1140535) Investigate the performance implications of simply + // calling the 3d version above with: + // transform(m11, m12, 0, 0, m21, m22, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1); + cc::PaintCanvas* c = GetOrCreatePaintCanvas(); if (!c) return; @@ -572,7 +806,7 @@ void BaseRenderingContext2D::transform(double m11, if (!GetState().IsTransformInvertible()) return; - c->concat(TransformationMatrixToSkMatrix(transform)); + c->concat(TransformationMatrix::ToSkM44(transform)); path_.Transform(transform.Inverse()); } @@ -590,7 +824,8 @@ void BaseRenderingContext2D::resetTransform() { // resetTransform() resolves the non-invertible CTM state. ModifiableState().ResetTransform(); - c->setMatrix(TransformationMatrixToSkMatrix(TransformationMatrix())); + // Set the SkCanvas' matrix to identity. + c->setMatrix(SkM44()); if (invertible_ctm) path_.Transform(ctm); @@ -611,37 +846,77 @@ void BaseRenderingContext2D::setTransform(double m11, return; resetTransform(); - // clamp to float to avoid float cast overflow when used as SkScalar - float fm11 = clampTo<float>(m11); - float fm12 = clampTo<float>(m12); - float fm21 = clampTo<float>(m21); - float fm22 = clampTo<float>(m22); - float fdx = clampTo<float>(dx); - float fdy = clampTo<float>(dy); + transform(m11, m12, m21, m22, dx, dy); +} - transform(fm11, fm12, fm21, fm22, fdx, fdy); +void BaseRenderingContext2D::setTransform(double m11, + double m12, + double m13, + double m14, + double m21, + double m22, + double m23, + double m24, + double m31, + double m32, + double m33, + double m34, + double m41, + double m42, + double m43, + double m44) { + if (!std::isfinite(m11) || !std::isfinite(m12) || !std::isfinite(m13) || + !std::isfinite(m14) || !std::isfinite(m21) || !std::isfinite(m22) || + !std::isfinite(m23) || !std::isfinite(m24) || !std::isfinite(m31) || + !std::isfinite(m32) || !std::isfinite(m33) || !std::isfinite(m34) || + !std::isfinite(m41) || !std::isfinite(m42) || !std::isfinite(m43) || + !std::isfinite(m44)) + return; + + resetTransform(); + transform(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, + m42, m43, m44); } -void BaseRenderingContext2D::setTransform(DOMMatrix2DInit* transform, +void BaseRenderingContext2D::setTransform(DOMMatrixInit* transform, ExceptionState& exception_state) { DOMMatrixReadOnly* m = - DOMMatrixReadOnly::fromMatrix2D(transform, exception_state); + DOMMatrixReadOnly::fromMatrix(transform, exception_state); if (!m) return; - setTransform(m->m11(), m->m12(), m->m21(), m->m22(), m->m41(), m->m42()); + // The new canvas 2d API supports 3d transforms. + // https://github.com/fserb/canvas2D/blob/master/spec/perspective-transforms.md + // If it is not enabled, throw 3d information away. + if (RuntimeEnabledFeatures::NewCanvas2DAPIEnabled()) { + setTransform(m->m11(), m->m12(), m->m13(), m->m14(), m->m21(), m->m22(), + m->m23(), m->m24(), m->m31(), m->m32(), m->m33(), m->m34(), + m->m41(), m->m42(), m->m43(), m->m44()); + } else { + setTransform(m->m11(), m->m12(), m->m21(), m->m22(), m->m41(), m->m42()); + } } DOMMatrix* BaseRenderingContext2D::getTransform() { const TransformationMatrix& t = GetState().GetTransform(); DOMMatrix* m = DOMMatrix::Create(); - m->setA(t.A()); - m->setB(t.B()); - m->setC(t.C()); - m->setD(t.D()); - m->setE(t.E()); - m->setF(t.F()); + m->setM11(t.M11()); + m->setM12(t.M12()); + m->setM13(t.M13()); + m->setM14(t.M14()); + m->setM21(t.M21()); + m->setM22(t.M22()); + m->setM23(t.M23()); + m->setM24(t.M24()); + m->setM31(t.M31()); + m->setM32(t.M32()); + m->setM33(t.M33()); + m->setM34(t.M34()); + m->setM41(t.M41()); + m->setM42(t.M42()); + m->setM43(t.M43()); + m->setM44(t.M44()); return m; } @@ -983,63 +1258,6 @@ static inline void ClipRectsToImageRect(const FloatRect& image_rect, dst_rect->Move(offset); } -static inline CanvasImageSource* ToImageSourceInternal( - const CanvasImageSourceUnion& value, - ExceptionState& exception_state) { - if (value.IsCSSImageValue()) { - return value.GetAsCSSImageValue(); - } - if (value.IsHTMLImageElement()) - return value.GetAsHTMLImageElement(); - if (value.IsHTMLVideoElement()) { - HTMLVideoElement* video = value.GetAsHTMLVideoElement(); - video->VideoWillBeDrawnToCanvas(); - return video; - } - if (value.IsSVGImageElement()) - return value.GetAsSVGImageElement(); - if (value.IsHTMLCanvasElement()) { - if (static_cast<HTMLCanvasElement*>(value.GetAsHTMLCanvasElement()) - ->Size() - .IsEmpty()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "The image argument is a canvas element with a width " - "or height of 0."); - return nullptr; - } - return value.GetAsHTMLCanvasElement(); - } - if (value.IsImageBitmap()) { - if (static_cast<ImageBitmap*>(value.GetAsImageBitmap())->IsNeutered()) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - "The image source is detached"); - return nullptr; - } - return value.GetAsImageBitmap(); - } - if (value.IsOffscreenCanvas()) { - if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas()) - ->IsNeutered()) { - exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, - "The image source is detached"); - return nullptr; - } - if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas()) - ->Size() - .IsEmpty()) { - exception_state.ThrowDOMException( - DOMExceptionCode::kInvalidStateError, - "The image argument is an OffscreenCanvas element " - "with a width or height of 0."); - return nullptr; - } - return value.GetAsOffscreenCanvas(); - } - NOTREACHED(); - return nullptr; -} - void BaseRenderingContext2D::drawImage( ScriptState* script_state, const CanvasImageSourceUnion& image_source, @@ -1047,10 +1265,11 @@ void BaseRenderingContext2D::drawImage( double y, ExceptionState& exception_state) { CanvasImageSource* image_source_internal = - ToImageSourceInternal(image_source, exception_state); + ToCanvasImageSource(image_source, exception_state); if (!image_source_internal) return; - RespectImageOrientationEnum respect_orientation = RespectImageOrientation(); + RespectImageOrientationEnum respect_orientation = + RespectImageOrientationInternal(image_source_internal); FloatSize default_object_size(Width(), Height()); FloatSize source_rect_size = image_source_internal->ElementSize( default_object_size, respect_orientation); @@ -1070,12 +1289,13 @@ void BaseRenderingContext2D::drawImage( double height, ExceptionState& exception_state) { CanvasImageSource* image_source_internal = - ToImageSourceInternal(image_source, exception_state); + ToCanvasImageSource(image_source, exception_state); if (!image_source_internal) return; FloatSize default_object_size(this->Width(), this->Height()); FloatSize source_rect_size = image_source_internal->ElementSize( - default_object_size, RespectImageOrientation()); + default_object_size, + RespectImageOrientationInternal(image_source_internal)); drawImage(script_state, image_source_internal, 0, 0, source_rect_size.Width(), source_rect_size.Height(), x, y, width, height, exception_state); } @@ -1093,7 +1313,7 @@ void BaseRenderingContext2D::drawImage( double dh, ExceptionState& exception_state) { CanvasImageSource* image_source_internal = - ToImageSourceInternal(image_source, exception_state); + ToCanvasImageSource(image_source, exception_state); if (!image_source_internal) return; drawImage(script_state, image_source_internal, sx, sy, sw, sh, dx, dy, dw, dh, @@ -1131,12 +1351,14 @@ bool BaseRenderingContext2D::ShouldDrawImageAntialiased( dest_rect.Height() * fabs(height_expansion) < 1; } -void BaseRenderingContext2D::DrawImageInternal(cc::PaintCanvas* c, - CanvasImageSource* image_source, - Image* image, - const FloatRect& src_rect, - const FloatRect& dst_rect, - const PaintFlags* flags) { +void BaseRenderingContext2D::DrawImageInternal( + cc::PaintCanvas* c, + CanvasImageSource* image_source, + Image* image, + const FloatRect& src_rect, + const FloatRect& dst_rect, + const SkSamplingOptions& sampling, + const PaintFlags* flags) { int initial_save_count = c->getSaveCount(); PaintFlags image_flags = *flags; @@ -1177,7 +1399,8 @@ void BaseRenderingContext2D::DrawImageInternal(cc::PaintCanvas* c, // We always use the image-orientation property on the canvas element // because the alternative would result in complex rules depending on // the source of the image. - RespectImageOrientationEnum respect_orientation = RespectImageOrientation(); + RespectImageOrientationEnum respect_orientation = + RespectImageOrientationInternal(image_source); FloatRect corrected_src_rect = src_rect; if (respect_orientation == kRespectImageOrientation && !image->HasDefaultOrientation()) { @@ -1185,7 +1408,7 @@ void BaseRenderingContext2D::DrawImageInternal(cc::PaintCanvas* c, image->SizeAsFloat(kRespectImageOrientation), src_rect); } image_flags.setAntiAlias(ShouldDrawImageAntialiased(dst_rect)); - image->Draw(c, image_flags, dst_rect, corrected_src_rect, + image->Draw(c, image_flags, dst_rect, corrected_src_rect, sampling, respect_orientation, Image::kDoNotClampImageToSourceRect, Image::kSyncDecode); } else { @@ -1263,8 +1486,8 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state, FloatRect src_rect = NormalizeRect(FloatRect(fsx, fsy, fsw, fsh)); FloatRect dst_rect = NormalizeRect(FloatRect(fdx, fdy, fdw, fdh)); - FloatSize image_size = - image_source->ElementSize(default_object_size, RespectImageOrientation()); + FloatSize image_size = image_source->ElementSize( + default_object_size, RespectImageOrientationInternal(image_source)); ClipRectsToImageRect(FloatRect(FloatPoint(), image_size), &src_rect, &dst_rect); @@ -1285,8 +1508,11 @@ void BaseRenderingContext2D::drawImage(ScriptState* script_state, [this, &image_source, &image, &src_rect, dst_rect]( cc::PaintCanvas* c, const PaintFlags* flags) // draw lambda { + SkSamplingOptions sampling( + flags ? flags->getFilterQuality() : kNone_SkFilterQuality, + SkSamplingOptions::kMedium_asMipmapLinear); DrawImageInternal(c, image_source, image.get(), src_rect, dst_rect, - flags); + sampling, flags); }, [this, &dst_rect](const SkIRect& clip_bounds) // overdraw test lambda { return RectContainsTransformedRect(dst_rect, clip_bounds); }, @@ -1445,7 +1671,7 @@ CanvasPattern* BaseRenderingContext2D::createPattern( const String& repetition_type, ExceptionState& exception_state) { CanvasImageSource* image_source_internal = - ToImageSourceInternal(image_source, exception_state); + ToCanvasImageSource(image_source, exception_state); if (!image_source_internal) { return nullptr; } @@ -1483,7 +1709,8 @@ CanvasPattern* BaseRenderingContext2D::createPattern( String::Format("The canvas %s is 0.", image_source ->ElementSize(default_object_size, - RespectImageOrientation()) + RespectImageOrientationInternal( + image_source)) .Width() ? "height" : "width")); @@ -1543,56 +1770,44 @@ bool BaseRenderingContext2D::ComputeDirtyRect( return true; } -ImageDataColorSettings* -BaseRenderingContext2D::GetColorSettingsAsImageDataColorSettings() const { - ImageDataColorSettings* color_settings = ImageDataColorSettings::Create(); - color_settings->setColorSpace(ColorSpaceAsString()); - if (PixelFormat() == CanvasPixelFormat::kF16) - color_settings->setStorageFormat(kFloat32ArrayStorageFormatName); - return color_settings; -} - ImageData* BaseRenderingContext2D::createImageData( ImageData* image_data, ExceptionState& exception_state) const { - ImageData* result = nullptr; - ImageDataColorSettings* color_settings = - GetColorSettingsAsImageDataColorSettings(); - result = ImageData::Create(image_data->Size(), color_settings); - if (!result) - exception_state.ThrowRangeError("Out of memory at ImageData creation"); - return result; + return ImageData::ValidateAndCreate( + image_data->Size().Width(), image_data->Size().Height(), base::nullopt, + image_data->getSettings(), exception_state, + ImageData::Context2DErrorMode); } ImageData* BaseRenderingContext2D::createImageData( int sw, int sh, ExceptionState& exception_state) const { - if (!sw || !sh) { - exception_state.ThrowDOMException( - DOMExceptionCode::kIndexSizeError, - String::Format("The source %s is 0.", sw ? "height" : "width")); - return nullptr; - } - - IntSize size(abs(sw), abs(sh)); - ImageData* result = nullptr; - ImageDataColorSettings* color_settings = - GetColorSettingsAsImageDataColorSettings(); - result = ImageData::Create(size, color_settings); - - if (!result) - exception_state.ThrowRangeError("Out of memory at ImageData creation"); - return result; + ImageDataSettings* image_data_settings = ImageDataSettings::Create(); + image_data_settings->setColorSpace(kSRGBCanvasColorSpaceName); + image_data_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName); + return ImageData::ValidateAndCreate(std::abs(sw), std::abs(sh), base::nullopt, + image_data_settings, exception_state, + ImageData::Context2DErrorMode); } ImageData* BaseRenderingContext2D::createImageData( - unsigned width, - unsigned height, - ImageDataColorSettings* color_settings, + unsigned sw, + unsigned sh, + ImageDataSettings* image_data_settings, ExceptionState& exception_state) const { - return ImageData::CreateImageData(width, height, color_settings, - exception_state); + return ImageData::ValidateAndCreate(sw, sh, base::nullopt, + image_data_settings, exception_state, + ImageData::Context2DErrorMode); +} + +ImageData* BaseRenderingContext2D::getImageData( + int sx, + int sy, + int sw, + int sh, + ExceptionState& exception_state) { + return getImageDataInternal(sx, sy, sw, sh, nullptr, exception_state); } ImageData* BaseRenderingContext2D::getImageData( @@ -1600,6 +1815,18 @@ ImageData* BaseRenderingContext2D::getImageData( int sy, int sw, int sh, + ImageDataSettings* image_data_settings, + ExceptionState& exception_state) { + return getImageDataInternal(sx, sy, sw, sh, image_data_settings, + exception_state); +} + +ImageData* BaseRenderingContext2D::getImageDataInternal( + int sx, + int sy, + int sw, + int sh, + ImageDataSettings* image_data_settings, ExceptionState& exception_state) { if (!base::CheckMul(sw, sh).IsValid<int>()) { exception_state.ThrowRangeError("Out of memory at ImageData creation"); @@ -1643,91 +1870,144 @@ ImageData* BaseRenderingContext2D::getImageData( return nullptr; } - IntRect image_data_rect(sx, sy, sw, sh); - bool hasResourceProvider = CanCreateCanvas2dResourceProvider(); - ImageDataColorSettings* color_settings = - GetColorSettingsAsImageDataColorSettings(); - if (!hasResourceProvider || isContextLost()) { - ImageData* result = - ImageData::Create(image_data_rect.Size(), color_settings); - if (!result) - exception_state.ThrowRangeError("Out of memory at ImageData creation"); - return result; + const IntRect image_data_rect(sx, sy, sw, sh); + + if (!image_data_settings) { + image_data_settings = ImageDataSettings::Create(); + image_data_settings->setColorSpace(kSRGBCanvasColorSpaceName); + image_data_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName); + } + + const ImageDataStorageFormat storage_format = + ImageData::GetImageDataStorageFormat( + image_data_settings->storageFormat()); + if (!CanCreateCanvas2dResourceProvider() || isContextLost()) { + return ImageData::ValidateAndCreate(sw, sh, base::nullopt, + image_data_settings, exception_state, + ImageData::Context2DErrorMode); } - const CanvasColorParams& color_params = ColorParams(); // Deferred offscreen canvases might have recorded commands, make sure // that those get drawn here FinalizeFrame(); - scoped_refptr<StaticBitmapImage> snapshot = GetImage(); // TODO(crbug.com/1101055): Remove the check for NewCanvas2DAPI flag once // released. - // New Canvas2D API utilizes willReadFrequently attribute that let the users - // indicate if a canvas will be read frequently through getImageData, thus - // uses CPU rendering from the start in such cases. (crbug.com/1090180) + // TODO(crbug.com/1090180): New Canvas2D API utilizes willReadFrequently + // attribute that let the users indicate if a canvas will be read frequently + // through getImageData, thus uses CPU rendering from the start in such cases. if (!RuntimeEnabledFeatures::NewCanvas2DAPIEnabled()) { - // GetImagedata is faster in Unaccelerated canvases - if (IsAccelerated()) { + // GetImagedata is faster in Unaccelerated canvases. + // In Desynchronized canvas disabling the acceleration will break + // putImageData: crbug.com/1112060. + if (IsAccelerated() && !IsDesynchronized()) { DisableAcceleration(); base::UmaHistogramEnumeration("Blink.Canvas.GPUFallbackToCPU", GPUFallbackToCPUScenario::kGetImageData); } } - size_t size_in_bytes; - if (!StaticBitmapImage::GetSizeInBytes(image_data_rect, color_params) - .AssignIfValid(&size_in_bytes) || - size_in_bytes > v8::TypedArray::kMaxLength) { - exception_state.ThrowRangeError("Out of memory at ImageData creation"); - return nullptr; - } - - bool may_have_stray_area = - IsAccelerated() // GPU readback may fail silently. - || StaticBitmapImage::MayHaveStrayArea(snapshot, image_data_rect); - ArrayBufferContents::InitializationPolicy initialization_policy = - may_have_stray_area ? ArrayBufferContents::kZeroInitialize - : ArrayBufferContents::kDontInitialize; + scoped_refptr<StaticBitmapImage> snapshot = GetImage(); - ArrayBufferContents contents( - size_in_bytes, 1, ArrayBufferContents::kNotShared, initialization_policy); - if (contents.DataLength() != size_in_bytes) { - exception_state.ThrowRangeError("Out of memory at ImageData creation"); - return nullptr; + // Compute the ImageData's SkImageInfo; + SkImageInfo image_info; + { + SkColorType color_type = kRGBA_8888_SkColorType; + switch (storage_format) { + case kUint8ClampedArrayStorageFormat: + color_type = kRGBA_8888_SkColorType; + break; + case kUint16ArrayStorageFormat: + color_type = kR16G16B16A16_unorm_SkColorType; + break; + case kFloat32ArrayStorageFormat: + color_type = kRGBA_F32_SkColorType; + break; + default: + NOTREACHED(); + } + sk_sp<SkColorSpace> color_space = CanvasColorSpaceToSkColorSpace( + CanvasColorSpaceFromName(image_data_settings->colorSpace())); + image_info = SkImageInfo::Make(sw, sh, color_type, kUnpremul_SkAlphaType, + color_space); } - if (!StaticBitmapImage::CopyToByteArray( - snapshot, - base::span<uint8_t>(reinterpret_cast<uint8_t*>(contents.Data()), - contents.DataLength()), - image_data_rect, color_params)) { - exception_state.ThrowRangeError("Failed to copy image data"); - return nullptr; + // Compute the size of and allocate |contents|, the ArrayContentsBuffer. + ArrayBufferContents contents; + const size_t data_size_bytes = image_info.computeMinByteSize(); + { + if (data_size_bytes > std::numeric_limits<unsigned int>::max()) { + exception_state.ThrowRangeError( + "Buffer size exceeds maximum heap object size."); + return nullptr; + } + if (SkImageInfo::ByteSizeOverflowed(data_size_bytes) || + data_size_bytes > v8::TypedArray::kMaxLength) { + exception_state.ThrowRangeError("Out of memory at ImageData creation"); + return nullptr; + } + ArrayBufferContents::InitializationPolicy initialization_policy = + ArrayBufferContents::kDontInitialize; + if (IsAccelerated()) { + // GPU readback may fail silently. + initialization_policy = ArrayBufferContents::kZeroInitialize; + } else if (snapshot) { + // Zero-initialize if some of the readback area is out of bounds. + if (image_data_rect.X() < 0 || image_data_rect.Y() < 0 || + image_data_rect.MaxX() > snapshot->Size().Width() || + image_data_rect.MaxY() > snapshot->Size().Height()) { + initialization_policy = ArrayBufferContents::kZeroInitialize; + } + } + contents = + ArrayBufferContents(data_size_bytes, 1, ArrayBufferContents::kNotShared, + initialization_policy); + if (contents.DataLength() != data_size_bytes) { + exception_state.ThrowRangeError("Out of memory at ImageData creation"); + return nullptr; + } } - // Convert pixels to proper storage format if needed - if (PixelFormat() != CanvasColorParams::GetNativeCanvasPixelFormat()) { - ImageDataStorageFormat storage_format = - ImageData::GetImageDataStorageFormat(color_settings->storageFormat()); - NotShared<DOMArrayBufferView> array_buffer_view = - ImageData::ConvertPixelsFromCanvasPixelFormatToImageDataStorageFormat( - contents, PixelFormat(), storage_format); - return ImageData::Create(image_data_rect.Size(), array_buffer_view, - color_settings); - } - if (size_in_bytes > std::numeric_limits<unsigned int>::max()) { - exception_state.ThrowRangeError( - "Buffer size exceeds maximum heap object size."); - return nullptr; + // Read pixels into |contents|. + if (snapshot) { + const bool read_pixels_successful = + snapshot->PaintImageForCurrentFrame().readPixels( + image_info, contents.Data(), image_info.minRowBytes(), sx, sy); + if (!read_pixels_successful) { + SkIRect bounds = + snapshot->PaintImageForCurrentFrame().GetSkImageInfo().bounds(); + DCHECK(!bounds.intersect(SkIRect::MakeXYWH(sx, sy, sw, sh))); + } } - DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(std::move(contents)); - ImageData* imageData = ImageData::Create( - image_data_rect.Size(), - NotShared<DOMUint8ClampedArray>(DOMUint8ClampedArray::Create( - array_buffer, 0, static_cast<unsigned int>(size_in_bytes))), - color_settings); + // Wrap |contents| in an ImageData. + DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(std::move(contents)); + NotShared<DOMArrayBufferView> data_array; + switch (storage_format) { + case kUint8ClampedArrayStorageFormat: { + size_t num_elements = data_size_bytes; + data_array = NotShared<DOMArrayBufferView>( + DOMUint8ClampedArray::Create(array_buffer, 0, num_elements)); + break; + } + case kUint16ArrayStorageFormat: { + size_t num_elements = data_size_bytes / 2; + data_array = NotShared<DOMArrayBufferView>( + DOMUint16Array::Create(array_buffer, 0, num_elements)); + break; + } + case kFloat32ArrayStorageFormat: { + size_t num_elements = data_size_bytes / 4; + data_array = NotShared<DOMArrayBufferView>( + DOMFloat32Array::Create(array_buffer, 0, num_elements)); + break; + } + default: + NOTREACHED(); + } + ImageData* image_data = ImageData::ValidateAndCreate( + sw, sh, data_array, image_data_settings, exception_state, + ImageData::Context2DErrorMode); if (!IsPaint2D()) { int scaled_time = getScaledElapsedTime( @@ -1740,8 +2020,7 @@ ImageData* BaseRenderingContext2D::getImageData( "Blink.Canvas.GetImageDataScaledDuration.CPU", scaled_time); } } - - return imageData; + return image_data; } int BaseRenderingContext2D::getScaledElapsedTime(float width, @@ -1779,7 +2058,7 @@ void BaseRenderingContext2D::putImageData(ImageData* data, } base::TimeTicks start_time = base::TimeTicks::Now(); - if (data->BufferBase()->IsDetached()) { + if (data->IsBufferBaseDetached()) { exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, "The source data has been detached."); return; @@ -1828,32 +2107,39 @@ void BaseRenderingContext2D::putImageData(ImageData* data, // in sRGB color space and use uint8 pixel storage format. We use RGBA pixel // order for both ImageData and CanvasResourceProvider, therefore no // additional swizzling is needed. - CanvasColorParams data_color_params = data->GetCanvasColorParams(); - CanvasColorParams context_color_params = - CanvasColorParams(ColorParams().ColorSpace(), PixelFormat(), kNonOpaque); - - size_t data_length; - if (!base::CheckMul(data->Size().Area(), context_color_params.BytesPerPixel()) - .AssignIfValid(&data_length)) - return; - - if (data_color_params.ColorSpace() != context_color_params.ColorSpace() || - data_color_params.PixelFormat() != context_color_params.PixelFormat() || - PixelFormat() == CanvasPixelFormat::kF16) { - std::unique_ptr<uint8_t[]> converted_pixels(new uint8_t[data_length]); - if (data->ImageDataInCanvasColorSettings( - ColorParams().ColorSpace(), PixelFormat(), converted_pixels.get(), - kRGBAColorType)) { - PutByteArray(converted_pixels.get(), - IntSize(data->width(), data->height()), source_rect, - IntPoint(dest_offset)); + SkPixmap data_pixmap = data->GetSkPixmap(); + CanvasColorParams data_color_params( + data->GetCanvasColorSpace(), + data->GetImageDataStorageFormat() != kUint8ClampedArrayStorageFormat + ? CanvasPixelFormat::kF16 + : CanvasPixelFormat::kUint8, + kNonOpaque); + if (data_color_params.ColorSpace() != GetCanvas2DColorParams().ColorSpace() || + data_color_params.PixelFormat() != + GetCanvas2DColorParams().PixelFormat() || + GetCanvas2DColorParams().PixelFormat() == CanvasPixelFormat::kF16) { + SkImageInfo converted_info = data_pixmap.info(); + converted_info = + converted_info.makeColorType(GetCanvas2DColorParams().GetSkColorType()); + converted_info = converted_info.makeColorSpace( + GetCanvas2DColorParams().GetSkColorSpace()); + if (converted_info.colorType() == kN32_SkColorType) + converted_info = converted_info.makeColorType(kRGBA_8888_SkColorType); + + const size_t converted_data_bytes = converted_info.computeMinByteSize(); + const size_t converted_row_bytes = converted_info.minRowBytes(); + if (SkImageInfo::ByteSizeOverflowed(converted_data_bytes)) + return; + std::unique_ptr<uint8_t[]> converted_pixels( + new uint8_t[converted_data_bytes]); + if (data_pixmap.readPixels(converted_info, converted_pixels.get(), + converted_row_bytes)) { + PutByteArray( + SkPixmap(converted_info, converted_pixels.get(), converted_row_bytes), + source_rect, IntPoint(dest_offset)); } } else { - // TODO(crbug.com/1115317): PutByteArray works with uint8 only. It should be - // compatible with uint16 and float32. - PutByteArray(data->data().GetAsUint8ClampedArray()->Data(), - IntSize(data->width(), data->height()), source_rect, - IntPoint(dest_offset)); + PutByteArray(data_pixmap, source_rect, IntPoint(dest_offset)); } if (!IsPaint2D()) { @@ -1871,59 +2157,37 @@ void BaseRenderingContext2D::putImageData(ImageData* data, DidDraw(dest_rect); } -void BaseRenderingContext2D::PutByteArray(const unsigned char* source, - const IntSize& source_size, +void BaseRenderingContext2D::PutByteArray(const SkPixmap& source, const IntRect& source_rect, const IntPoint& dest_point) { if (!IsCanvas2DBufferValid()) return; - uint8_t bytes_per_pixel = ColorParams().BytesPerPixel(); - - DCHECK_GT(source_rect.Width(), 0); - DCHECK_GT(source_rect.Height(), 0); - int origin_x = source_rect.X(); + DCHECK(IntRect(0, 0, source.width(), source.height()).Contains(source_rect)); int dest_x = dest_point.X() + source_rect.X(); DCHECK_GE(dest_x, 0); DCHECK_LT(dest_x, Width()); - DCHECK_GE(origin_x, 0); - DCHECK_LT(origin_x, source_rect.MaxX()); - - int origin_y = source_rect.Y(); int dest_y = dest_point.Y() + source_rect.Y(); DCHECK_GE(dest_y, 0); DCHECK_LT(dest_y, Height()); - DCHECK_GE(origin_y, 0); - DCHECK_LT(origin_y, source_rect.MaxY()); - const base::CheckedNumeric<size_t> src_bytes_per_row_checked = - base::CheckMul(bytes_per_pixel, source_size.Width()); - if (!src_bytes_per_row_checked.IsValid()) { - VLOG(1) << "Invalid sizes"; - return; - } - const size_t src_bytes_per_row = src_bytes_per_row_checked.ValueOrDie(); - const void* src_addr = - source + origin_y * src_bytes_per_row + origin_x * bytes_per_pixel; - - SkAlphaType alpha_type; - if (kOpaque == ColorParams().GetOpacityMode()) { + SkImageInfo info = + source.info().makeWH(source_rect.Width(), source_rect.Height()); + if (kOpaque == GetCanvas2DColorParams().GetOpacityMode()) { // If the surface is opaque, tell it that we are writing opaque // pixels. Writing non-opaque pixels to opaque is undefined in // Skia. There is some discussion about whether it should be // defined in skbug.com/6157. For now, we can get the desired // behavior (memcpy) by pretending the write is opaque. - alpha_type = kOpaque_SkAlphaType; + info = info.makeAlphaType(kOpaque_SkAlphaType); } else { - alpha_type = kUnpremul_SkAlphaType; + info = info.makeAlphaType(kUnpremul_SkAlphaType); } - - SkImageInfo info = SkImageInfo::Make( - source_rect.Width(), source_rect.Height(), ColorParams().GetSkColorType(), - alpha_type, ColorParams().GetSkColorSpace()); if (info.colorType() == kN32_SkColorType) info = info.makeColorType(kRGBA_8888_SkColorType); - WritePixels(info, src_addr, src_bytes_per_row, dest_x, dest_y); + + WritePixels(info, source.addr(source_rect.X(), source_rect.Y()), + source.rowBytes(), dest_x, dest_y); } void BaseRenderingContext2D::InflateStrokeRect(FloatRect& rect) const { @@ -2077,6 +2341,10 @@ String BaseRenderingContext2D::fontKerning() const { return FontDescription::ToString(GetState().GetFontKerning()); } +String BaseRenderingContext2D::fontStretch() const { + return FontDescription::ToString(GetState().GetFontStretch()); +} + String BaseRenderingContext2D::fontVariantCaps() const { return FontDescription::ToString(GetState().GetFontVariantCaps()); } diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h index 57554d72d86..679622118be 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h @@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/geometry/dom_matrix.h" #include "third_party/blink/renderer/core/html/canvas/image_data.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_gradient.h" +#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.h" @@ -24,9 +25,6 @@ class Color; class Image; class Path2D; -typedef CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas - CanvasImageSourceUnion; - class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, public CanvasPath { public: @@ -82,21 +80,61 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, void reset(); void scale(double sx, double sy); + void scale(double sx, double sy, double sz); void rotate(double angle_in_radians); + void rotate3d(double rx, double ry, double rz); + void rotateAxis(double axisX, + double axisY, + double axisZ, + double angle_in_radians); void translate(double tx, double ty); + void translate(double tx, double ty, double tz); + void perspective(double length); void transform(double m11, double m12, double m21, double m22, double dx, double dy); + void transform(double m11, + double m12, + double m13, + double m14, + double m21, + double m22, + double m23, + double m24, + double m31, + double m32, + double m33, + double m34, + double m41, + double m42, + double m43, + double m44); + void setTransform(double m11, + double m12, + double m13, + double m14, + double m21, + double m22, + double m23, + double m24, + double m31, + double m32, + double m33, + double m34, + double m41, + double m42, + double m43, + double m44); void setTransform(double m11, double m12, double m21, double m22, double dx, double dy); - void setTransform(DOMMatrix2DInit*, ExceptionState&); + void setTransform(DOMMatrixInit*, ExceptionState&); virtual DOMMatrix* getTransform(); virtual void resetTransform(); @@ -185,16 +223,25 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, ImageData* createImageData(int width, int height, ExceptionState&) const; ImageData* createImageData(unsigned, unsigned, - ImageDataColorSettings*, + ImageDataSettings*, ExceptionState&) const; // For deferred canvases this will have the side effect of drawing recorded // commands in order to finalize the frame - virtual ImageData* getImageData(int sx, - int sy, - int sw, - int sh, - ExceptionState&); + ImageData* getImageData(int sx, int sy, int sw, int sh, ExceptionState&); + ImageData* getImageData(int sx, + int sy, + int sw, + int sh, + ImageDataSettings*, + ExceptionState&); + virtual ImageData* getImageDataInternal(int sx, + int sy, + int sw, + int sh, + ImageDataSettings*, + ExceptionState&); + void putImageData(ImageData*, int dx, int dy, ExceptionState&); void putImageData(ImageData*, int dx, @@ -244,17 +291,15 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, virtual bool HasAlpha() const = 0; + virtual bool IsDesynchronized() const { + NOTREACHED(); + return false; + } + virtual bool isContextLost() const = 0; virtual void WillDrawImage(CanvasImageSource*) const {} - virtual String ColorSpaceAsString() const { - return kSRGBCanvasColorSpaceName; - } - virtual CanvasPixelFormat PixelFormat() const { - return CanvasColorParams::GetNativeCanvasPixelFormat(); - } - void RestoreMatrixClipStack(cc::PaintCanvas*) const; String textAlign() const; @@ -268,6 +313,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, String textRendering() const; String fontKerning() const; + String fontStretch() const; String fontVariantCaps() const; void Trace(Visitor*) const override; @@ -350,7 +396,10 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, void UnwindStateStack(); - virtual CanvasColorParams ColorParams() const { return CanvasColorParams(); } + // The implementations of this will query the CanvasColorParams from the + // CanvasRenderingContext. + virtual CanvasColorParams GetCanvas2DColorParams() const = 0; + virtual bool WritePixels(const SkImageInfo& orig_info, const void* pixels, size_t row_bytes, @@ -389,6 +438,15 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, static const char kNormalKerningString[]; static const char kNoneKerningString[]; static const char kNormalVariantString[]; + static const char kUltraCondensedString[]; + static const char kExtraCondensedString[]; + static const char kCondensedString[]; + static const char kSemiCondensedString[]; + static const char kNormalStretchString[]; + static const char kSemiExpandedString[]; + static const char kExpandedString[]; + static const char kExtraExpandedString[]; + static const char kUltraExpandedString[]; static const char kSmallCapsVariantString[]; static const char kAllSmallCapsVariantString[]; static const char kPetiteVariantString[]; @@ -434,6 +492,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, Image*, const FloatRect& src_rect, const FloatRect& dst_rect, + const SkSamplingOptions&, const PaintFlags*); void ClipInternal(const Path&, const String& winding_rule_string); @@ -464,10 +523,7 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, // such as tainting from a filter applied to the canvas. void SetOriginTaintedByContent(); - ImageDataColorSettings* GetColorSettingsAsImageDataColorSettings() const; - - void PutByteArray(const unsigned char* source, - const IntSize& source_size, + void PutByteArray(const SkPixmap& source, const IntRect& source_rect, const IntPoint& dest_point); virtual bool IsCanvas2DBufferValid() const { @@ -482,6 +538,9 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin, void IdentifiabilityMaybeUpdateForStyleUnion( const StringOrCanvasGradientOrCanvasPattern& style); + RespectImageOrientationEnum RespectImageOrientationInternal( + CanvasImageSource*); + bool origin_tainted_by_content_; DISALLOW_COPY_AND_ASSIGN(BaseRenderingContext2D); diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc new file mode 100644 index 00000000000..87478d8b386 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.cc @@ -0,0 +1,187 @@ +// Copyright 2020 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 "third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h" +#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/layout/layout_block_flow.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" +#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h" +#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" +#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h" +#include "third_party/blink/renderer/core/paint/paint_info.h" +#include "third_party/blink/renderer/core/style/computed_style.h" +#include "third_party/blink/renderer/platform/fonts/font_description.h" +#include "third_party/blink/renderer/platform/graphics/graphics_context.h" +#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" + +namespace blink { + +void CanvasFormattedText::Trace(Visitor* visitor) const { + visitor->Trace(text_runs_); + ScriptWrappable::Trace(visitor); +} + +CanvasFormattedText* CanvasFormattedText::Create( + ExecutionContext* execution_context, + const String text) { + CanvasFormattedText* canvas_formatted_text = + MakeGarbageCollected<CanvasFormattedText>(execution_context); + CanvasFormattedTextRun* run = + MakeGarbageCollected<CanvasFormattedTextRun>(execution_context, text); + canvas_formatted_text->text_runs_.push_back(run); + canvas_formatted_text->block_->AddChild(run->GetLayoutObject()); + return canvas_formatted_text; +} + +CanvasFormattedText::CanvasFormattedText(ExecutionContext* execution_context) { + scoped_refptr<ComputedStyle> style = ComputedStyle::Create(); + style->SetDisplay(EDisplay::kBlock); + // Refrain from extending the use of document, apart from creating layout + // block flow. In the future we should handle execution_context's from worker + // threads that do not have a document. + auto* window = To<LocalDOMWindow>(execution_context); + block_ = LayoutBlockFlow::CreateAnonymous(window->document(), style, + LegacyLayout::kAuto); + block_->SetIsLayoutNGObjectForCanvasFormattedText(true); +} + +void CanvasFormattedText::Dispose() { + // Detach all the anonymous children we added, since block_->Destroy will + // destroy them. We want the lifetime of the children to be managed by their + // corresponding CanvasFormattedTextRun and not destroyed at this point. + while (block_->FirstChild()) { + block_->RemoveChild(block_->FirstChild()); + } + AllowDestroyingLayoutObjectInFinalizerScope scope; + if (block_) + block_->Destroy(); +} + +LayoutBlockFlow* CanvasFormattedText::GetLayoutBlock( + Document& document, + const FontDescription& defaultFont) { + scoped_refptr<ComputedStyle> style = ComputedStyle::Create(); + style->SetDisplay(EDisplay::kBlock); + style->SetFontDescription(defaultFont); + block_->SetStyle(style); + return block_; +} + +CanvasFormattedTextRun* CanvasFormattedText::appendRun( + CanvasFormattedTextRun* run, + ExceptionState& exception_state) { + if (!CheckRunIsNotParented(run, &exception_state)) + return nullptr; + text_runs_.push_back(run); + block_->AddChild(run->GetLayoutObject()); + return run; +} + +CanvasFormattedTextRun* CanvasFormattedText::setRun( + unsigned index, + CanvasFormattedTextRun* run, + ExceptionState& exception_state) { + if (!CheckRunsIndexBound(index, &exception_state) || + !CheckRunIsNotParented(run, &exception_state)) + return nullptr; + block_->AddChild(run->GetLayoutObject(), + text_runs_[index]->GetLayoutObject()); + block_->RemoveChild(text_runs_[index]->GetLayoutObject()); + text_runs_[index] = run; + return text_runs_[index]; +} + +CanvasFormattedTextRun* CanvasFormattedText::insertRun( + unsigned index, + CanvasFormattedTextRun* run, + ExceptionState& exception_state) { + if (!CheckRunIsNotParented(run, &exception_state)) + return nullptr; + if (index == text_runs_.size()) + return appendRun(run, exception_state); + if (!CheckRunsIndexBound(index, &exception_state)) + return nullptr; + block_->AddChild(run->GetLayoutObject(), + text_runs_[index]->GetLayoutObject()); + text_runs_.insert(index, run); + return text_runs_[index]; +} + +void CanvasFormattedText::deleteRun(unsigned index, + unsigned length, + ExceptionState& exception_state) { + if (!CheckRunsIndexBound(index, &exception_state)) + return; + // Protect against overflow, do not perform math like index + length < + // text_runs_.size(). The length passed in can be close to INT_MAX. + if (text_runs_.size() - index < length) { + exception_state.ThrowDOMException( + DOMExceptionCode::kIndexSizeError, + ExceptionMessages::IndexExceedsMaximumBound("length", length, + text_runs_.size() - index)); + return; + } + + for (wtf_size_t i = index; i < index + length; i++) { + block_->RemoveChild(text_runs_[i]->GetLayoutObject()); + } + block_->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation( + layout_invalidation_reason::kCanvasFormattedTextRunChange); + text_runs_.EraseAt(static_cast<wtf_size_t>(index), + static_cast<wtf_size_t>(length)); +} + +sk_sp<PaintRecord> CanvasFormattedText::PaintFormattedText( + Document& document, + const FontDescription& font, + double x, + double y, + double wrap_width, + FloatRect& bounds) { + LayoutBlockFlow* block = GetLayoutBlock(document, font); + NGBlockNode block_node(block); + NGInlineNode node(block); + // Call IsEmptyInline to force prepare layout. + if (node.IsEmptyInline()) + return nullptr; + + // TODO(sushraja) Once we add support for writing mode on the canvas formatted + // text, fix this to be not hardcoded horizontal top to bottom. + NGConstraintSpaceBuilder builder( + WritingMode::kHorizontalTb, + {WritingMode::kHorizontalTb, TextDirection::kLtr}, + /* is_new_fc */ true); + LayoutUnit available_logical_width(wrap_width); + LogicalSize available_size = {available_logical_width, kIndefiniteSize}; + builder.SetAvailableSize(available_size); + NGConstraintSpace space = builder.ToConstraintSpace(); + scoped_refptr<const NGLayoutResult> block_results = + block_node.Layout(space, nullptr); + const auto& fragment = + To<NGPhysicalBoxFragment>(block_results->PhysicalFragment()); + block->RecalcInlineChildrenVisualOverflow(); + bounds = FloatRect(block->PhysicalVisualOverflowRect()); + + PaintController paint_controller(PaintController::Usage::kTransient); + paint_controller.UpdateCurrentPaintChunkProperties(nullptr, + PropertyTreeState::Root()); + GraphicsContext graphics_context(paint_controller); + PhysicalOffset physical_offset((LayoutUnit(x)), (LayoutUnit(y))); + NGBoxFragmentPainter box_fragment_painter(fragment); + PaintInfo paint_info(graphics_context, CullRect::Infinite(), + PaintPhase::kForeground, kGlobalPaintNormalPhase, + kPaintLayerPaintingRenderingClipPathAsMask | + kPaintLayerPaintingRenderingResourceSubtree); + box_fragment_painter.PaintObject(paint_info, physical_offset); + paint_controller.CommitNewDisplayItems(); + paint_controller.FinishCycle(); + sk_sp<PaintRecord> recording = + paint_controller.GetPaintArtifact().GetPaintRecord( + PropertyTreeState::Root()); + return recording; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h new file mode 100644 index 00000000000..f3284c1eeba --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h @@ -0,0 +1,129 @@ +// Copyright 2020 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_H_ + +#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text_run.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/bindings/exception_messages.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/text/bidi_resolver.h" +#include "third_party/blink/renderer/platform/text/bidi_text_run.h" +#include "third_party/blink/renderer/platform/text/text_direction.h" +#include "third_party/blink/renderer/platform/text/text_run_iterator.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +class LayoutBlockFlow; +class FontDescription; +class Document; + +class MODULES_EXPORT CanvasFormattedText final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + USING_PRE_FINALIZER(CanvasFormattedText, Dispose); + + public: + static CanvasFormattedText* Create(ExecutionContext* execution_context) { + return MakeGarbageCollected<CanvasFormattedText>(execution_context); + } + + static CanvasFormattedText* Create(ExecutionContext* execution_context, + const String text); + + static CanvasFormattedText* Create(ExecutionContext* execution_context, + CanvasFormattedTextRun* run, + ExceptionState& exception_state) { + CanvasFormattedText* canvas_formatted_text = + MakeGarbageCollected<CanvasFormattedText>(execution_context); + canvas_formatted_text->appendRun(run, exception_state); + return canvas_formatted_text; + } + + explicit CanvasFormattedText(ExecutionContext* execution_context); + CanvasFormattedText(const CanvasFormattedText&) = delete; + CanvasFormattedText& operator=(const CanvasFormattedText&) = delete; + + void Trace(Visitor* visitor) const override; + + unsigned length() const { return text_runs_.size(); } + + bool CheckRunsIndexBound(uint32_t index, + ExceptionState* exception_state) const { + if (index >= text_runs_.size()) { + if (exception_state) { + exception_state->ThrowDOMException( + DOMExceptionCode::kIndexSizeError, + ExceptionMessages::IndexExceedsMaximumBound("index", index, + text_runs_.size())); + } + return false; + } + return true; + } + + bool CheckRunIsNotParented(CanvasFormattedTextRun* run, + ExceptionState* exception_state) const { + if (run->GetLayoutObject() && run->GetLayoutObject()->Parent()) { + if (exception_state) { + exception_state->ThrowDOMException( + DOMExceptionCode::kInvalidModificationError, + "The run is already a part of a formatted text. Remove it from " + "that formatted text before insertion."); + } + return false; + } + return true; + } + + CanvasFormattedTextRun* getRun(unsigned index, + ExceptionState& exception_state) const { + if (!CheckRunsIndexBound(index, &exception_state)) + return nullptr; + return text_runs_[index]; + } + + CanvasFormattedTextRun* appendRun(CanvasFormattedTextRun* run, + ExceptionState& exception_state); + + CanvasFormattedTextRun* setRun(unsigned index, + CanvasFormattedTextRun* run, + ExceptionState& exception_state); + + CanvasFormattedTextRun* insertRun(unsigned index, + CanvasFormattedTextRun* run, + ExceptionState& exception_state); + + void deleteRun(unsigned index, ExceptionState& exception_state) { + deleteRun(index, 1, exception_state); + } + + void deleteRun(unsigned index, + unsigned length, + ExceptionState& exception_state); + + LayoutBlockFlow* GetLayoutBlock(Document& document, + const FontDescription& defaultFont); + + sk_sp<PaintRecord> PaintFormattedText(Document& document, + const FontDescription& font, + double x, + double y, + double wrap_width, + FloatRect& bounds); + + void Dispose(); + + private: + HeapVector<Member<CanvasFormattedTextRun>> text_runs_; + LayoutBlockFlow* block_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_H_ diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl new file mode 100644 index 00000000000..0e3b846cf6e --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.idl @@ -0,0 +1,24 @@ +// Copyright 2020 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. +[ + RuntimeEnabled=CanvasFormattedText, + Exposed=Window +] +interface CanvasFormattedText{ + [CallWith=ExecutionContext] constructor(); + [CallWith=ExecutionContext] constructor(DOMString text); + [CallWith=ExecutionContext, RaisesException] constructor(CanvasFormattedTextRun text); + + [RaisesException] getter CanvasFormattedTextRun getRun(unsigned long index); + [RaisesException] CanvasFormattedTextRun appendRun( + CanvasFormattedTextRun newRun); + [RaisesException] setter CanvasFormattedTextRun setRun( + unsigned long index, CanvasFormattedTextRun run); + [RaisesException] CanvasFormattedTextRun insertRun( + unsigned long index, CanvasFormattedTextRun run); + [RaisesException] void deleteRun(unsigned long index); + [RaisesException] void deleteRun(unsigned long index, unsigned long length); + + readonly attribute unsigned long length; +};
\ No newline at end of file diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc new file mode 100644 index 00000000000..a09607b2a83 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.cc @@ -0,0 +1,34 @@ +// Copyright 2021 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 "third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h" + +namespace blink { + +CanvasFormattedTextRun::CanvasFormattedTextRun( + ExecutionContext* execution_context, + const String text) + : text_(text) { + scoped_refptr<ComputedStyle> style = ComputedStyle::Create(); + style->SetDisplay(EDisplay::kInline); + // Refrain from extending the use of document, apart from creating layout + // text. In the future we should handle execution_context's from worker + // threads that do not have a document. + auto* window = To<LocalDOMWindow>(execution_context); + layout_text_ = + LayoutText::CreateAnonymous(*(window->document()), std::move(style), + text.Impl(), LegacyLayout::kAuto); + layout_text_->SetIsLayoutNGObjectForCanvasFormattedText(true); +} + +void CanvasFormattedTextRun::Dispose() { + AllowDestroyingLayoutObjectInFinalizerScope scope; + if (layout_text_) + layout_text_->Destroy(); +} + +void CanvasFormattedTextRun::Trace(Visitor* visitor) const { + ScriptWrappable::Trace(visitor); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h new file mode 100644 index 00000000000..5818ae82442 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.h @@ -0,0 +1,50 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_RUN_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_RUN_H_ + +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/core/layout/layout_text.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +class MODULES_EXPORT CanvasFormattedTextRun final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + USING_PRE_FINALIZER(CanvasFormattedTextRun, Dispose); + + public: + static CanvasFormattedTextRun* Create(ExecutionContext* execution_context, + const String text) { + return MakeGarbageCollected<CanvasFormattedTextRun>(execution_context, + text); + } + + CanvasFormattedTextRun(ExecutionContext*, const String text); + CanvasFormattedTextRun(const CanvasFormattedTextRun&) = delete; + CanvasFormattedTextRun& operator=(const CanvasFormattedTextRun&) = delete; + + String text() const { return text_; } + void setText(const String text) { text_ = text; } + + unsigned length() const { return text_.length(); } + + LayoutText* GetLayoutObject() { return layout_text_; } + + void Trace(Visitor* visitor) const override; + + void Dispose(); + + private: + String text_; + + LayoutText* layout_text_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_FORMATTED_TEXT_RUN_H_ diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl new file mode 100644 index 00000000000..7e1ea4f1a93 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text_run.idl @@ -0,0 +1,12 @@ +// Copyright 2021 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. +[ + RuntimeEnabled=CanvasFormattedText, + Exposed=Window +] +interface CanvasFormattedTextRun{ + [CallWith = ExecutionContext] constructor(DOMString text); + + attribute DOMString text; +};
\ No newline at end of file diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc new file mode 100644 index 00000000000..b388139d389 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.cc @@ -0,0 +1,82 @@ +// Copyright 2021 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 "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h" + +#include "third_party/blink/renderer/core/css/cssom/css_url_image_value.h" +#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" +#include "third_party/blink/renderer/core/html/html_image_element.h" +#include "third_party/blink/renderer/core/html/media/html_video_element.h" +#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" +#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h" +#include "third_party/blink/renderer/core/svg/svg_image_element.h" +#include "third_party/blink/renderer/modules/webcodecs/video_frame.h" + +namespace blink { + +CanvasImageSource* ToCanvasImageSource(const CanvasImageSourceUnion& value, + ExceptionState& exception_state) { + if (value.IsCSSImageValue()) + return value.GetAsCSSImageValue(); + if (value.IsHTMLImageElement()) + return value.GetAsHTMLImageElement(); + if (value.IsHTMLVideoElement()) { + HTMLVideoElement* video = value.GetAsHTMLVideoElement(); + video->VideoWillBeDrawnToCanvas(); + return video; + } + if (value.IsSVGImageElement()) + return value.GetAsSVGImageElement(); + if (value.IsHTMLCanvasElement()) { + if (static_cast<HTMLCanvasElement*>(value.GetAsHTMLCanvasElement()) + ->Size() + .IsEmpty()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "The image argument is a canvas element with a width " + "or height of 0."); + return nullptr; + } + return value.GetAsHTMLCanvasElement(); + } + if (value.IsImageBitmap()) { + if (static_cast<ImageBitmap*>(value.GetAsImageBitmap())->IsNeutered()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "The image source is detached"); + return nullptr; + } + return value.GetAsImageBitmap(); + } + if (value.IsOffscreenCanvas()) { + if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas()) + ->IsNeutered()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "The image source is detached"); + return nullptr; + } + if (static_cast<OffscreenCanvas*>(value.GetAsOffscreenCanvas()) + ->Size() + .IsEmpty()) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + "The image argument is an OffscreenCanvas element " + "with a width or height of 0."); + return nullptr; + } + return value.GetAsOffscreenCanvas(); + } + if (value.IsVideoFrame()) { + auto* video_frame = static_cast<VideoFrame*>(value.GetAsVideoFrame()); + if (!video_frame->frame()) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, + "The VideoFrame has been closed"); + return nullptr; + } + return video_frame; + } + NOTREACHED(); + return nullptr; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h new file mode 100644 index 00000000000..f003578953b --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h @@ -0,0 +1,24 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_IMAGE_SOURCE_UTIL_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_IMAGE_SOURCE_UTIL_H_ + +#include "third_party/blink/renderer/bindings/modules/v8/canvas_image_source.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" + +namespace blink { +class CanvasImageSource; + +using CanvasImageSourceUnion = + CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvasOrVideoFrame; + +MODULES_EXPORT CanvasImageSource* ToCanvasImageSource( + const CanvasImageSourceUnion& value, + ExceptionState& exception_state); + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_CANVAS2D_CANVAS_IMAGE_SOURCE_UTIL_H_ diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc index bd3bf105d7a..6a67606bfee 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_path.cc @@ -50,10 +50,7 @@ namespace blink { void CanvasPath::closePath() { if (path_.IsEmpty()) return; - - FloatRect bound_rect = path_.BoundingRect(); - if (bound_rect.Width() || bound_rect.Height()) - path_.CloseSubpath(); + path_.CloseSubpath(); } void CanvasPath::moveTo(double double_x, double double_y) { diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc index 22d3464e6e5..b3ef16c347a 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.cc @@ -38,8 +38,6 @@ #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h" #include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h" -#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h" -#include "third_party/blink/public/common/privacy_budget/identifiable_surface.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/bindings/modules/v8/rendering_context.h" @@ -245,6 +243,9 @@ void CanvasRenderingContext2D::DidSetSurfaceSize() { void CanvasRenderingContext2D::Trace(Visitor* visitor) const { visitor->Trace(hit_region_manager_); + visitor->Trace(dispatch_context_lost_event_timer_); + visitor->Trace(dispatch_context_restored_event_timer_); + visitor->Trace(try_restore_context_event_timer_); visitor->Trace(filter_operations_); CanvasRenderingContext::Trace(visitor); BaseRenderingContext2D::Trace(visitor); @@ -307,12 +308,8 @@ void CanvasRenderingContext2D::WillDrawImage(CanvasImageSource* source) const { canvas()->WillDrawImageTo2DContext(source); } -String CanvasRenderingContext2D::ColorSpaceAsString() const { - return CanvasRenderingContext::ColorSpaceAsString(); -} - -CanvasColorParams CanvasRenderingContext2D::ColorParams() const { - return CanvasRenderingContext::ColorParams(); +CanvasColorParams CanvasRenderingContext2D::GetCanvas2DColorParams() const { + return CanvasRenderingContext::CanvasRenderingContextColorParams(); } bool CanvasRenderingContext2D::WritePixels(const SkImageInfo& orig_info, @@ -330,10 +327,6 @@ void CanvasRenderingContext2D::WillOverwriteCanvas() { canvas()->GetCanvas2DLayerBridge()->WillOverwriteCanvas(); } -CanvasPixelFormat CanvasRenderingContext2D::PixelFormat() const { - return ColorParams().PixelFormat(); -} - void CanvasRenderingContext2D::Reset() { // This is a multiple inheritance bootstrap BaseRenderingContext2D::reset(); @@ -655,11 +648,7 @@ void CanvasRenderingContext2D::UpdateFilterReferences( filter_operations_ = filters; } -void CanvasRenderingContext2D::ResourceContentChanged(InvalidationModeMask) { - ResourceElementChanged(); -} - -void CanvasRenderingContext2D::ResourceElementChanged() { +void CanvasRenderingContext2D::ResourceContentChanged(SVGResource*) { ClearFilterReferences(); GetState().ClearResolvedFilter(); } @@ -690,20 +679,15 @@ scoped_refptr<StaticBitmapImage> blink::CanvasRenderingContext2D::GetImage() { return canvas()->GetCanvas2DLayerBridge()->NewImageSnapshot(); } -ImageData* CanvasRenderingContext2D::getImageData( +ImageData* CanvasRenderingContext2D::getImageDataInternal( int sx, int sy, int sw, int sh, + ImageDataSettings* image_data_settings, ExceptionState& exception_state) { - const IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken( - IdentifiableSurface::Type::kCanvasReadback, GetContextType()); - if (IdentifiabilityStudySettings::Get()->ShouldSample(surface)) { - blink::IdentifiabilityMetricBuilder(ukm_source_id_) - .Set(surface, 0) - .Record(ukm_recorder_); - } - return BaseRenderingContext2D::getImageData(sx, sy, sw, sh, exception_state); + return BaseRenderingContext2D::getImageDataInternal( + sx, sy, sw, sh, image_data_settings, exception_state); } void CanvasRenderingContext2D::FinalizeFrame() { @@ -873,6 +857,39 @@ void CanvasRenderingContext2D::setFontKerning( ModifiableState().SetFontKerning(kerning, Host()->GetFontSelector()); } +void CanvasRenderingContext2D::setFontStretch(const String& font_stretch) { + if (!GetState().HasRealizedFont()) + setFont(font()); + + String font_stretch_string = font_stretch.LowerASCII(); + FontSelectionValue stretch_vale; + if (font_stretch_string == kUltraCondensedString) + stretch_vale = UltraCondensedWidthValue(); + else if (font_stretch_string == kExtraCondensedString) + stretch_vale = ExtraCondensedWidthValue(); + else if (font_stretch_string == kCondensedString) + stretch_vale = CondensedWidthValue(); + else if (font_stretch_string == kSemiCondensedString) + stretch_vale = SemiCondensedWidthValue(); + else if (font_stretch_string == kNormalStretchString) + stretch_vale = NormalWidthValue(); + else if (font_stretch_string == kSemiExpandedString) + stretch_vale = SemiExpandedWidthValue(); + else if (font_stretch_string == kExpandedString) + stretch_vale = ExpandedWidthValue(); + else if (font_stretch_string == kExtraExpandedString) + stretch_vale = ExtraExpandedWidthValue(); + else if (font_stretch_string == kUltraExpandedString) + stretch_vale = UltraExpandedWidthValue(); + else + return; + + if (GetState().GetFontStretch() == stretch_vale) + return; + + ModifiableState().SetFontStretch(stretch_vale, Host()->GetFontSelector()); +} + void CanvasRenderingContext2D::setFontVariantCaps( const String& font_variant_caps_string) { if (!GetState().HasRealizedFont()) @@ -952,6 +969,28 @@ TextMetrics* CanvasRenderingContext2D::measureText(const String& text) { GetState().GetTextAlign(), text); } +void CanvasRenderingContext2D::fillFormattedText( + CanvasFormattedText* formatted_text, + double x, + double y, + double wrap_width) { + if (!formatted_text) + return; + + if (!GetState().HasRealizedFont()) + setFont(font()); + + FloatRect bounds; + sk_sp<PaintRecord> recording = formatted_text->PaintFormattedText( + canvas()->GetDocument(), GetState().GetFontDescription(), x, y, + wrap_width, bounds); + Draw([recording](cc::PaintCanvas* c, const PaintFlags* flags) // draw lambda + { c->drawPicture(recording); }, + [](const SkIRect& rect) { return false; }, bounds, + CanvasRenderingContext2DState::PaintType::kFillPaintType, + CanvasRenderingContext2DState::kNoImage); +} + void CanvasRenderingContext2D::DrawTextInternal( const String& text, double x, @@ -1099,8 +1138,8 @@ CanvasRenderingContext2D::getContextAttributes() const { CanvasRenderingContext2DSettings::Create(); settings->setAlpha(CreationAttributes().alpha); if (RuntimeEnabledFeatures::CanvasColorManagementEnabled()) { - settings->setColorSpace(ColorSpaceAsString()); - settings->setPixelFormat(PixelFormatAsString()); + settings->setColorSpace(GetCanvas2DColorParams().GetColorSpaceAsString()); + settings->setPixelFormat(GetCanvas2DColorParams().GetPixelFormatAsString()); } settings->setDesynchronized(Host()->LowLatencyEnabled()); if (RuntimeEnabledFeatures::NewCanvas2DAPIEnabled()) @@ -1151,7 +1190,11 @@ void CanvasRenderingContext2D::DrawFocusRing(const Path& path) { if (!GetOrCreatePaintCanvas()) return; - SkColor color = LayoutTheme::GetTheme().FocusRingColor().Rgb(); + // TODO(crbug.com/929098) Need to pass an appropriate color scheme here. + SkColor color = + LayoutTheme::GetTheme() + .FocusRingColor(ComputedStyle::InitialStyle().UsedColorScheme()) + .Rgb(); const int kFocusRingWidth = 5; DrawPlatformFocusRing(path.GetSkPath(), GetPaintCanvas(), color, /*width=*/kFocusRingWidth, /*radius=*/kFocusRingWidth); diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h index 4e6faada14c..0243cee60c5 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h @@ -31,6 +31,7 @@ #include "base/macros.h" #include "services/metrics/public/cpp/ukm_recorder.h" +#include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_formatted_text.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_canvas_rendering_context_2d_settings.h" #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h" #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h" @@ -39,6 +40,7 @@ #include "third_party/blink/renderer/core/style/filter_operations.h" #include "third_party/blink/renderer/core/svg/svg_resource_client.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h" +#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_formatted_text.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h" #include "third_party/blink/renderer/modules/canvas/canvas2d/identifiability_study_helper.h" #include "third_party/blink/renderer/modules/modules_export.h" @@ -68,8 +70,8 @@ class HitTestCanvasResult; class Path2D; class TextMetrics; -typedef CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvas - CanvasImageSourceUnion; +using CanvasImageSourceUnion = + CSSImageValueOrHTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrImageBitmapOrOffscreenCanvasOrVideoFrame; class MODULES_EXPORT CanvasRenderingContext2D final : public CanvasRenderingContext, @@ -131,6 +133,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final void setTextRendering(const String&); void setFontKerning(const String&); + void setFontStretch(const String&); void setFontVariantCaps(const String&); void fillText(const String& text, double x, double y); @@ -141,6 +144,11 @@ class MODULES_EXPORT CanvasRenderingContext2D final CanvasRenderingContext2DSettings* getContextAttributes() const; + void fillFormattedText(CanvasFormattedText* formatted_text, + double x, + double y, + double wrap_width); + void drawFocusIfNeeded(Element*); void drawFocusIfNeeded(Path2D*, Element*); @@ -165,8 +173,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final String GetIdFromControl(const Element*) override; // SVGResourceClient implementation - void ResourceContentChanged(InvalidationModeMask) override; - void ResourceElementChanged() override; + void ResourceContentChanged(SVGResource*) override; void UpdateFilterReferences(const FilterOperations&); void ClearFilterReferences(); @@ -210,13 +217,16 @@ class MODULES_EXPORT CanvasRenderingContext2D final void Trace(Visitor*) const override; - ImageData* getImageData(int sx, - int sy, - int sw, - int sh, - ExceptionState&) override; + ImageData* getImageDataInternal(int sx, + int sy, + int sw, + int sh, + ImageDataSettings*, + ExceptionState&) final; - CanvasColorParams ColorParamsForTest() const { return ColorParams(); } + CanvasColorParams ColorParamsForTest() const { + return GetCanvas2DColorParams(); + } IdentifiableToken IdentifiableTextToken() const override { return identifiability_study_helper_.GetToken(); @@ -231,7 +241,7 @@ class MODULES_EXPORT CanvasRenderingContext2D final } protected: - CanvasColorParams ColorParams() const override; + CanvasColorParams GetCanvas2DColorParams() const override; bool WritePixels(const SkImageInfo& orig_info, const void* pixels, size_t row_bytes, @@ -267,14 +277,14 @@ class MODULES_EXPORT CanvasRenderingContext2D final return CanvasRenderingContext::kContext2D; } - String ColorSpaceAsString() const override; - CanvasPixelFormat PixelFormat() const override; - bool IsRenderingContext2D() const override { return true; } bool IsComposited() const override; bool IsAccelerated() const override; bool IsOriginTopLeft() const override; bool HasAlpha() const override { return CreationAttributes().alpha; } + bool IsDesynchronized() const override { + return CreationAttributes().desynchronized; + } void SetIsInHiddenPage(bool) override; void SetIsBeingDisplayed(bool) override; void Stop() final; @@ -289,10 +299,12 @@ class MODULES_EXPORT CanvasRenderingContext2D final LostContextMode context_lost_mode_; bool context_restorable_; unsigned try_restore_context_attempt_count_; - TaskRunnerTimer<CanvasRenderingContext2D> dispatch_context_lost_event_timer_; - TaskRunnerTimer<CanvasRenderingContext2D> + HeapTaskRunnerTimer<CanvasRenderingContext2D> + dispatch_context_lost_event_timer_; + HeapTaskRunnerTimer<CanvasRenderingContext2D> dispatch_context_restored_event_timer_; - TaskRunnerTimer<CanvasRenderingContext2D> try_restore_context_event_timer_; + HeapTaskRunnerTimer<CanvasRenderingContext2D> + try_restore_context_event_timer_; FilterOperations filter_operations_; HashMap<String, FontDescription> fonts_resolved_using_current_style_; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl index 78e1c791ef2..f2ea9e5ee4c 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.idl @@ -39,7 +39,8 @@ typedef (CSSImageValue or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or - OffscreenCanvas) CanvasImageSource; + OffscreenCanvas or + VideoFrame) CanvasImageSource; enum CanvasFillRule { "nonzero", "evenodd" }; enum ImageSmoothingQuality {"low", "medium", "high"}; @@ -57,11 +58,22 @@ interface CanvasRenderingContext2D { // transformations (default transform is the identity matrix) void scale(unrestricted double x, unrestricted double y); + [RuntimeEnabled=NewCanvas2DAPI] void scale(unrestricted double x, unrestricted double y, unrestricted double z); void rotate(unrestricted double angle); + [RuntimeEnabled=NewCanvas2DAPI] void rotate3d(unrestricted double angleX, unrestricted double angleY, unrestricted double angleZ); + [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle); void translate(unrestricted double x, unrestricted double y); + [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z); + [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length); void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); + [RuntimeEnabled=NewCanvas2DAPI] void transform( + unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14, + unrestricted double m21, unrestricted double m22, unrestricted double m23, unrestricted double m24, + unrestricted double m31, unrestricted double m32, unrestricted double m33, unrestricted double m34, + unrestricted double m41, unrestricted double m42, unrestricted double m43, unrestricted double m44 + ); void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); - [RaisesException] void setTransform(optional DOMMatrix2DInit transform = {}); + [RaisesException] void setTransform(optional DOMMatrixInit transform = {}); DOMMatrix getTransform(); void resetTransform(); @@ -116,6 +128,9 @@ interface CanvasRenderingContext2D { void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth); TextMetrics measureText(DOMString text); + // Render entire CanvasFormattedText with line wrapping (one-shot) + [RuntimeEnabled=CanvasFormattedText] void fillFormattedText(CanvasFormattedText formattedText, double x, double y, double wrapWidth); + // drawing images [CallWith=ScriptState, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y); [CallWith=ScriptState, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y, unrestricted double width, unrestricted double height); @@ -134,7 +149,8 @@ interface CanvasRenderingContext2D { [RaisesException] void putImageData(ImageData imagedata, [EnforceRange] long dx, [EnforceRange] long dy, [EnforceRange] long dirtyX, [EnforceRange] long dirtyY, [EnforceRange] long dirtyWidth, [EnforceRange] long dirtyHeight); // https://github.com/WICG/canvas-color-space/blob/master/CanvasColorSpaceProposal.md - [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(unsigned long sw, unsigned long sh, ImageDataColorSettings imageDataColorSettings); + [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData getImageData([EnforceRange] long sx, [EnforceRange] long sy, [EnforceRange] long sw, [EnforceRange] long sh, ImageDataSettings imageDataSettings); + [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData([EnforceRange] long sw, [EnforceRange] long sh, ImageDataSettings imageDataSettings); // Context state // Should be merged with WebGL counterpart in CanvasRenderingContext, once no-longer experimental @@ -159,11 +175,12 @@ interface CanvasRenderingContext2D { attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start") attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic") attribute DOMString direction; // "inherit", "rtl", "ltr" (default: "inherit") - [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0) - [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0) [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontKerning; // "auto", "normal", "none" (default: "auto") + [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontStretch; // "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" (default: normal) [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontVariantCaps; // "normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps" (default: "normal") + [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0) [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString textRendering; // "auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision" (default: auto) + [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0) }; -CanvasRenderingContext2D includes CanvasPath;
\ No newline at end of file +CanvasRenderingContext2D includes CanvasPath; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc index 28d4ca0cf6d..d030abae93f 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h" #include <memory> +#include "base/metrics/histogram_functions.h" #include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h" #include "third_party/blink/renderer/core/css/resolver/style_builder.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" @@ -28,7 +29,6 @@ #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/skia/include/effects/SkDashPathEffect.h" -#include "third_party/skia/include/effects/SkDropShadowImageFilter.h" static const char defaultFont[] = "10px sans-serif"; static const char defaultFilter[] = "none"; @@ -105,6 +105,7 @@ CanvasRenderingContext2DState::CanvasRenderingContext2DState( word_spacing_(other.word_spacing_), text_rendering_mode_(other.text_rendering_mode_), font_kerning_(other.font_kerning_), + font_stretch_(other.font_stretch_), font_variant_caps_(other.font_variant_caps_), realized_font_(other.realized_font_), is_transform_invertible_(other.is_transform_invertible_), @@ -291,6 +292,16 @@ void CanvasRenderingContext2DState::SetFontKerning( SetFont(font_description, selector); } +void CanvasRenderingContext2DState::SetFontStretch( + FontSelectionValue font_stretch, + FontSelector* selector) { + DCHECK(realized_font_); + FontDescription font_description(GetFontDescription()); + font_description.SetStretch(font_stretch); + font_stretch_ = font_stretch; + SetFont(font_description, selector); +} + void CanvasRenderingContext2DState::SetFontVariantCaps( FontDescription::FontVariantCaps font_variant_caps, FontSelector* selector) { @@ -486,24 +497,24 @@ SkDrawLooper* CanvasRenderingContext2DState::ShadowAndForegroundDrawLooper() sk_sp<PaintFilter> CanvasRenderingContext2DState::ShadowOnlyImageFilter() const { + using ShadowMode = DropShadowPaintFilter::ShadowMode; if (!shadow_only_image_filter_) { const auto sigma = BlurRadiusToStdDev(shadow_blur_); shadow_only_image_filter_ = sk_make_sp<DropShadowPaintFilter>( shadow_offset_.Width(), shadow_offset_.Height(), sigma, sigma, - shadow_color_, SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, - nullptr); + shadow_color_, ShadowMode::kDrawShadowOnly, nullptr); } return shadow_only_image_filter_; } sk_sp<PaintFilter> CanvasRenderingContext2DState::ShadowAndForegroundImageFilter() const { + using ShadowMode = DropShadowPaintFilter::ShadowMode; if (!shadow_and_foreground_image_filter_) { const auto sigma = BlurRadiusToStdDev(shadow_blur_); shadow_and_foreground_image_filter_ = sk_make_sp<DropShadowPaintFilter>( shadow_offset_.Width(), shadow_offset_.Height(), sigma, sigma, - shadow_color_, - SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, nullptr); + shadow_color_, ShadowMode::kDrawShadowAndForeground, nullptr); } return shadow_and_foreground_image_filter_; } @@ -591,6 +602,9 @@ void CanvasRenderingContext2DState::UpdateFilterQuality() const { if (!image_smoothing_enabled_) { UpdateFilterQualityWithSkFilterQuality(kNone_SkFilterQuality); } else { + base::UmaHistogramExactLinear("Blink.Canvas.ImageSmoothingQuality", + static_cast<int>(image_smoothing_quality_), + static_cast<int>(kLast_SkFilterQuality) + 1); UpdateFilterQualityWithSkFilterQuality(image_smoothing_quality_); } } diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h index e4559b94190..237a1a8af61 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.h @@ -24,6 +24,12 @@ class CanvasStyle; class CSSValue; class Element; +enum ShadowMode { + kDrawShadowAndForeground, + kDrawShadowOnly, + kDrawForegroundOnly +}; + class CanvasRenderingContext2DState final : public GarbageCollected<CanvasRenderingContext2DState>, public FontSelectorClient { @@ -144,6 +150,9 @@ class CanvasRenderingContext2DState final FontSelector* selector); FontDescription::Kerning GetFontKerning() const { return font_kerning_; } + void SetFontStretch(FontSelectionValue font_stretch, FontSelector* selector); + FontSelectionValue GetFontStretch() const { return font_stretch_; } + void SetFontVariantCaps(FontDescription::FontVariantCaps font_kerning, FontSelector* selector); FontDescription::FontVariantCaps GetFontVariantCaps() const { @@ -267,6 +276,7 @@ class CanvasRenderingContext2DState final float word_spacing_{0}; TextRenderingMode text_rendering_mode_{TextRenderingMode::kAutoTextRendering}; FontDescription::Kerning font_kerning_{FontDescription::kAutoKerning}; + FontSelectionValue font_stretch_{NormalWidthValue()}; FontDescription::FontVariantCaps font_variant_caps_{ FontDescription::kCapsNormal}; diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc index 2dfcebff125..896a32b5cea 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc @@ -231,8 +231,8 @@ void CanvasRenderingContext2DTest::SetUp() { canvas_element_ = To<HTMLCanvasElement>(GetDocument().getElementById("c")); - full_image_data_ = ImageData::Create(IntSize(10, 10)); - partial_image_data_ = ImageData::Create(IntSize(2, 2)); + full_image_data_ = ImageData::Create(10, 10, ASSERT_NO_EXCEPTION); + partial_image_data_ = ImageData::Create(2, 2, ASSERT_NO_EXCEPTION); NonThrowableExceptionState exception_state; auto* opaque_gradient = @@ -310,12 +310,12 @@ class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge { class FakeCanvasResourceProvider : public CanvasResourceProvider { public: FakeCanvasResourceProvider(const IntSize& size, - CanvasColorParams color_params, + CanvasResourceParams params, RasterModeHint hint) : CanvasResourceProvider(CanvasResourceProvider::kBitmap, size, kLow_SkFilterQuality, - color_params, + params, /*is_origin_top_left=*/false, nullptr, nullptr), @@ -608,7 +608,7 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) { IntSize size(10, 10); std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider = - std::make_unique<FakeCanvasResourceProvider>(size, CanvasColorParams(), + std::make_unique<FakeCanvasResourceProvider>(size, CanvasResourceParams(), RasterModeHint::kPreferGPU); std::unique_ptr<FakeCanvas2DLayerBridge> fake_2d_layer_bridge = std::make_unique<FakeCanvas2DLayerBridge>(size, CanvasColorParams(), @@ -639,8 +639,8 @@ TEST_F(CanvasRenderingContext2DTest, GPUMemoryUpdateForAcceleratedCanvas) { std::make_unique<FakeCanvas2DLayerBridge>(size2, CanvasColorParams(), RasterModeHint::kPreferGPU); std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider2 = - std::make_unique<FakeCanvasResourceProvider>(size2, CanvasColorParams(), - RasterModeHint::kPreferGPU); + std::make_unique<FakeCanvasResourceProvider>( + size2, CanvasResourceParams(), RasterModeHint::kPreferGPU); anotherCanvas->SetResourceProviderForTesting( std::move(fake_resource_provider2), std::move(fake_2d_layer_bridge2), size2); @@ -757,6 +757,7 @@ static void TestDrawSingleHighBitDepthPNGOnCanvas( String filepath, CanvasRenderingContext2D* context, Document& document, + ImageDataSettings* color_setting, ScriptState* script_state) { scoped_refptr<SharedBuffer> pixel_buffer = test::ReadFromFile(filepath); ASSERT_EQ(false, pixel_buffer->IsEmpty()); @@ -782,10 +783,11 @@ static void TestDrawSingleHighBitDepthPNGOnCanvas( image_union.SetHTMLImageElement(image_element); context->drawImage(script_state, image_union, 0, 0, exception_state); - ImageData* image_data = context->getImageData(0, 0, 2, 2, exception_state); + ImageData* image_data = + context->getImageData(0, 0, 2, 2, color_setting, exception_state); ImageDataArray data_array = image_data->data(); ASSERT_TRUE(data_array.IsFloat32Array()); - DOMArrayBufferView* buffer_view = data_array.GetAsFloat32Array().View(); + DOMArrayBufferView* buffer_view = data_array.GetAsFloat32Array().Get(); ASSERT_EQ(16u, buffer_view->byteLength() / buffer_view->TypeSize()); float* actual_pixels = static_cast<float*>(buffer_view->BaseAddress()); @@ -826,6 +828,9 @@ static void TestDrawHighBitDepthPNGsOnWideGamutCanvas( StringBuilder path; path.Append(test::CoreTestDataPath()); path.Append("/png-16bit/"); + ImageDataSettings* color_setting = ImageDataSettings::Create(); + color_setting->setStorageFormat(kFloat32ArrayStorageFormatName); + color_setting->setColorSpace(canvas_color_space); for (auto interlace : interlace_status) { for (auto color_profile : color_profiles) { for (auto alpha : alpha_status) { @@ -837,7 +842,8 @@ static void TestDrawHighBitDepthPNGsOnWideGamutCanvas( full_path.Append(alpha); full_path.Append(".png"); TestDrawSingleHighBitDepthPNGOnCanvas(full_path.ToString(), context, - document, script_state); + document, color_setting, + script_state); } } } @@ -845,8 +851,8 @@ static void TestDrawHighBitDepthPNGsOnWideGamutCanvas( TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnP3Canvas) { TestDrawHighBitDepthPNGsOnWideGamutCanvas( - "p3", GetDocument(), Persistent<HTMLCanvasElement>(CanvasElement()), - GetScriptState()); + "display-p3", GetDocument(), + Persistent<HTMLCanvasElement>(CanvasElement()), GetScriptState()); } TEST_F(CanvasRenderingContext2DTest, DrawHighBitDepthPngOnRec2020Canvas) { @@ -897,14 +903,14 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( kRec2020CanvasColorSpaceName, kP3CanvasColorSpaceName}; CanvasPixelFormat canvas_pixel_formats[] = { - CanvasPixelFormat::kRGBA8, + CanvasPixelFormat::kUint8, CanvasPixelFormat::kF16, CanvasPixelFormat::kF16, CanvasPixelFormat::kF16, }; String canvas_pixel_format_names[] = { - kRGBA8CanvasPixelFormatName, kF16CanvasPixelFormatName, + kUint8CanvasPixelFormatName, kF16CanvasPixelFormatName, kF16CanvasPixelFormatName, kF16CanvasPixelFormatName, kF16CanvasPixelFormatName}; @@ -937,7 +943,7 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( EXPECT_EQ(data_length, data_f32->length()); ImageData* image_data = nullptr; - ImageDataColorSettings* color_settings = ImageDataColorSettings::Create(); + ImageDataSettings* image_data_settings = ImageDataSettings::Create(); int num_pixels = data_length / 4; // At most four bytes are needed for Float32 output per color component. @@ -947,7 +953,7 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( // Loop through different possible combinations of image data color space and // storage formats and create the respective test image data objects. for (unsigned i = 0; i < num_image_data_color_spaces; i++) { - color_settings->setColorSpace( + image_data_settings->setColorSpace( ImageData::CanvasColorSpaceName(image_data_color_spaces[i])); for (unsigned j = 0; j < num_image_data_storage_formats; j++) { @@ -955,24 +961,40 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( switch (image_data_storage_formats[j]) { case kUint8ClampedArrayStorageFormat: data_array = data_u8; - color_settings->setStorageFormat(kUint8ClampedArrayStorageFormatName); + image_data_settings->setStorageFormat( + kUint8ClampedArrayStorageFormatName); break; case kUint16ArrayStorageFormat: data_array = data_u16; - color_settings->setStorageFormat(kUint16ArrayStorageFormatName); + image_data_settings->setStorageFormat(kUint16ArrayStorageFormatName); break; case kFloat32ArrayStorageFormat: data_array = data_f32; - color_settings->setStorageFormat(kFloat32ArrayStorageFormatName); + image_data_settings->setStorageFormat(kFloat32ArrayStorageFormatName); break; default: NOTREACHED(); } - image_data = - ImageData::CreateForTest(IntSize(2, 2), data_array, color_settings); + image_data = ImageData::CreateForTest(IntSize(2, 2), data_array, + image_data_settings); + unsigned k = static_cast<unsigned>(canvas_colorspace_setting); + ImageDataSettings* canvas_color_setting = ImageDataSettings::Create(); + canvas_color_setting->setColorSpace( + ImageData::CanvasColorSpaceName(canvas_color_spaces[k])); + switch (canvas_pixel_formats[k]) { + case CanvasPixelFormat::kUint8: + canvas_color_setting->setStorageFormat( + kUint8ClampedArrayStorageFormatName); + break; + case CanvasPixelFormat::kF16: + canvas_color_setting->setStorageFormat( + kFloat32ArrayStorageFormatName); + break; + default: + NOTREACHED(); + } - unsigned k = (unsigned)(canvas_colorspace_setting); // Convert the original data used to create ImageData to the // canvas color space and canvas pixel format. EXPECT_TRUE( @@ -995,14 +1017,15 @@ void TestPutImageDataOnCanvasWithColorSpaceSettings( NonThrowableExceptionState exception_state; context->putImageData(image_data, 0, 0, exception_state); - void* pixels_from_get_image_data = - context->getImageData(0, 0, 2, 2, exception_state) - ->BufferBase() - ->Data(); + const void* pixels_from_get_image_data = + context + ->getImageData(0, 0, 2, 2, canvas_color_setting, exception_state) + ->GetSkPixmap() + .addr(); ColorCorrectionTestUtils::CompareColorCorrectedPixels( pixels_from_get_image_data, pixels_converted_manually.get(), num_pixels, - (canvas_pixel_formats[k] == CanvasPixelFormat::kRGBA8) + (canvas_pixel_formats[k] == CanvasPixelFormat::kUint8) ? kPixelFormat_8888 : kPixelFormat_ffff, kAlphaUnmultiplied, kUnpremulRoundTripTolerance); diff --git a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc index 4fecf3deee9..83c1620d804 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/canvas2d/canvas_style.cc @@ -73,7 +73,9 @@ static Color CurrentColor(HTMLCanvasElement* canvas) { } static mojom::blink::ColorScheme ColorScheme(HTMLCanvasElement* canvas) { - if (canvas && canvas->isConnected()) { + if (!canvas) + return mojom::blink::ColorScheme::kLight; + if (canvas->isConnected()) { if (auto* style = canvas->GetComputedStyle()) return style->UsedColorScheme(); } @@ -91,7 +93,7 @@ bool ParseColorOrCurrentColor(Color& parsed_color, case kParsedSystemColor: return true; case kParsedCurrentColor: - parsed_color = canvas ? CurrentColor(canvas) : Color::kBlack; + parsed_color = CurrentColor(canvas); return true; case kParseFailed: return false; diff --git a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc index 3ce12a41b15..106a7bb5c18 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc @@ -108,7 +108,7 @@ TEST_P(HTMLCanvasElementModuleTest, LowLatencyCanvasCompositorFrameOpacity) { auto context_provider = viz::TestContextProvider::Create(); context_provider->UnboundTestContextGL() ->set_supports_gpu_memory_buffer_format( - CanvasColorParams().GetBufferFormat(), true); + CanvasColorParams().GetAsResourceParams().GetBufferFormat(), true); InitializeSharedGpuContext(context_provider.get()); // To intercept SubmitCompositorFrame/SubmitCompositorFrameSync messages sent diff --git a/chromium/third_party/blink/renderer/modules/canvas/idls.gni b/chromium/third_party/blink/renderer/modules/canvas/idls.gni index 582575f4478..96740fd08c7 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/idls.gni +++ b/chromium/third_party/blink/renderer/modules/canvas/idls.gni @@ -5,6 +5,8 @@ import("//third_party/blink/renderer/config.gni") modules_idl_files = [ + "canvas2d/canvas_formatted_text.idl", + "canvas2d/canvas_formatted_text_run.idl", "canvas2d/canvas_gradient.idl", "canvas2d/canvas_pattern.idl", "canvas2d/canvas_rendering_context_2d.idl", @@ -22,6 +24,8 @@ modules_dictionary_idl_files = [ modules_dependency_idl_files = [ "canvas2d/canvas_path.idl", "htmlcanvas/html_canvas_element_module.idl", + "imagebitmap/window_create_image_bitmap.idl", + "imagebitmap/worker_create_image_bitmap.idl", "offscreencanvas/offscreen_canvas_module.idl", ] diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc new file mode 100644 index 00000000000..d111834f2af --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2013, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h" + +#include <memory> +#include <utility> + +#include "base/location.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h" +#include "third_party/blink/renderer/core/dom/dom_exception.h" +#include "third_party/blink/renderer/core/execution_context/execution_context.h" +#include "third_party/blink/renderer/core/fileapi/blob.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h" +#include "third_party/blink/renderer/core/html/canvas/image_data.h" +#include "third_party/blink/renderer/core/html/html_image_element.h" +#include "third_party/blink/renderer/core/html/media/html_video_element.h" +#include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" +#include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h" +#include "third_party/blink/renderer/core/svg/svg_image_element.h" +#include "third_party/blink/renderer/core/workers/worker_global_scope.h" +#include "third_party/blink/renderer/modules/webcodecs/video_frame.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h" +#include "third_party/blink/renderer/platform/instrumentation/histogram.h" +#include "third_party/blink/renderer/platform/instrumentation/use_counter.h" +#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" +#include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" +#include "third_party/blink/renderer/platform/wtf/shared_buffer.h" +#include "v8/include/v8.h" + +namespace blink { + +namespace { +// This enum is used in a UMA histogram. +enum CreateImageBitmapSource { + kCreateImageBitmapSourceBlob = 0, + kCreateImageBitmapSourceImageBitmap = 1, + kCreateImageBitmapSourceImageData = 2, + kCreateImageBitmapSourceHTMLCanvasElement = 3, + kCreateImageBitmapSourceHTMLImageElement = 4, + kCreateImageBitmapSourceHTMLVideoElement = 5, + kCreateImageBitmapSourceOffscreenCanvas = 6, + kCreateImageBitmapSourceSVGImageElement = 7, + kCreateImageBitmapSourceVideoFrame = 8, + kMaxValue = kCreateImageBitmapSourceVideoFrame, +}; + +} // namespace + +static inline ImageBitmapSource* ToImageBitmapSourceInternal( + const ImageBitmapSourceUnion& value, + const ImageBitmapOptions* options, + bool has_crop_rect) { + if (value.IsHTMLVideoElement()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceHTMLVideoElement); + return value.GetAsHTMLVideoElement(); + } + if (value.IsHTMLImageElement()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceHTMLImageElement); + return value.GetAsHTMLImageElement(); + } + if (value.IsSVGImageElement()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceSVGImageElement); + return value.GetAsSVGImageElement(); + } + if (value.IsHTMLCanvasElement()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceHTMLCanvasElement); + return value.GetAsHTMLCanvasElement(); + } + if (value.IsBlob()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceBlob); + return value.GetAsBlob(); + } + if (value.IsImageData()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceImageData); + return value.GetAsImageData(); + } + if (value.IsImageBitmap()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceImageBitmap); + return value.GetAsImageBitmap(); + } + if (value.IsOffscreenCanvas()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceOffscreenCanvas); + return value.GetAsOffscreenCanvas(); + } + if (value.IsVideoFrame()) { + UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.CreateImageBitmapSource", + kCreateImageBitmapSourceVideoFrame); + return value.GetAsVideoFrame(); + } + NOTREACHED(); + return nullptr; +} + +ScriptPromise ImageBitmapFactories::CreateImageBitmapFromBlob( + ScriptState* script_state, + ImageBitmapSource* bitmap_source, + base::Optional<IntRect> crop_rect, + const ImageBitmapOptions* options) { + DCHECK(script_state->ContextIsValid()); + ImageBitmapFactories& factory = From(*ExecutionContext::From(script_state)); + ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::Create( + factory, crop_rect, options, script_state); + factory.AddLoader(loader); + loader->LoadBlobAsync(static_cast<Blob*>(bitmap_source)); + return loader->Promise(); +} + +ScriptPromise ImageBitmapFactories::CreateImageBitmap( + ScriptState* script_state, + const ImageBitmapSourceUnion& bitmap_source, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + WebFeature feature = WebFeature::kCreateImageBitmap; + UseCounter::Count(ExecutionContext::From(script_state), feature); + ImageBitmapSource* bitmap_source_internal = + ToImageBitmapSourceInternal(bitmap_source, options, false); + if (!bitmap_source_internal) + return ScriptPromise(); + return CreateImageBitmap(script_state, bitmap_source_internal, + base::Optional<IntRect>(), options, exception_state); +} + +ScriptPromise ImageBitmapFactories::CreateImageBitmap( + ScriptState* script_state, + const ImageBitmapSourceUnion& bitmap_source, + int sx, + int sy, + int sw, + int sh, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + WebFeature feature = WebFeature::kCreateImageBitmap; + UseCounter::Count(ExecutionContext::From(script_state), feature); + ImageBitmapSource* bitmap_source_internal = + ToImageBitmapSourceInternal(bitmap_source, options, true); + if (!bitmap_source_internal) + return ScriptPromise(); + base::Optional<IntRect> crop_rect = IntRect(sx, sy, sw, sh); + return CreateImageBitmap(script_state, bitmap_source_internal, crop_rect, + options, exception_state); +} + +ScriptPromise ImageBitmapFactories::CreateImageBitmap( + ScriptState* script_state, + ImageBitmapSource* bitmap_source, + base::Optional<IntRect> crop_rect, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + if (crop_rect && (crop_rect->Width() == 0 || crop_rect->Height() == 0)) { + exception_state.ThrowRangeError(String::Format( + "The crop rect %s is 0.", crop_rect->Width() ? "height" : "width")); + return ScriptPromise(); + } + + if (bitmap_source->IsBlob()) { + return CreateImageBitmapFromBlob(script_state, bitmap_source, crop_rect, + options); + } + + if (bitmap_source->BitmapSourceSize().Width() == 0 || + bitmap_source->BitmapSourceSize().Height() == 0) { + exception_state.ThrowDOMException( + DOMExceptionCode::kInvalidStateError, + String::Format( + "The source image %s is 0.", + bitmap_source->BitmapSourceSize().Width() ? "height" : "width")); + return ScriptPromise(); + } + + return bitmap_source->CreateImageBitmap(script_state, crop_rect, options, + exception_state); +} + +const char ImageBitmapFactories::kSupplementName[] = "ImageBitmapFactories"; + +ImageBitmapFactories& ImageBitmapFactories::From(ExecutionContext& context) { + ImageBitmapFactories* supplement = + Supplement<ExecutionContext>::From<ImageBitmapFactories>(context); + if (!supplement) { + supplement = MakeGarbageCollected<ImageBitmapFactories>(); + Supplement<ExecutionContext>::ProvideTo(context, supplement); + } + return *supplement; +} + +void ImageBitmapFactories::AddLoader(ImageBitmapLoader* loader) { + pending_loaders_.insert(loader); +} + +void ImageBitmapFactories::DidFinishLoading(ImageBitmapLoader* loader) { + DCHECK(pending_loaders_.Contains(loader)); + pending_loaders_.erase(loader); +} + +void ImageBitmapFactories::Trace(Visitor* visitor) const { + visitor->Trace(pending_loaders_); + Supplement<ExecutionContext>::Trace(visitor); +} + +ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader( + ImageBitmapFactories& factory, + base::Optional<IntRect> crop_rect, + ScriptState* script_state, + const ImageBitmapOptions* options) + : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)), + loader_(std::make_unique<FileReaderLoader>( + FileReaderLoader::kReadAsArrayBuffer, + this, + GetExecutionContext()->GetTaskRunner(TaskType::kFileReading))), + factory_(&factory), + resolver_(MakeGarbageCollected<ScriptPromiseResolver>(script_state)), + crop_rect_(crop_rect), + options_(options) {} + +void ImageBitmapFactories::ImageBitmapLoader::LoadBlobAsync(Blob* blob) { + loader_->Start(blob->GetBlobDataHandle()); +} + +ImageBitmapFactories::ImageBitmapLoader::~ImageBitmapLoader() { + DCHECK(!loader_); +} + +void ImageBitmapFactories::ImageBitmapLoader::RejectPromise( + ImageBitmapRejectionReason reason) { + switch (reason) { + case kUndecodableImageBitmapRejectionReason: + resolver_->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kInvalidStateError, + "The source image could not be decoded.")); + break; + case kAllocationFailureImageBitmapRejectionReason: + resolver_->Reject(MakeGarbageCollected<DOMException>( + DOMExceptionCode::kInvalidStateError, + "The ImageBitmap could not be allocated.")); + break; + default: + NOTREACHED(); + } + loader_.reset(); + factory_->DidFinishLoading(this); +} + +void ImageBitmapFactories::ImageBitmapLoader::ContextDestroyed() { + if (loader_) + factory_->DidFinishLoading(this); + loader_.reset(); +} + +void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading() { + auto contents = loader_->TakeContents(); + loader_.reset(); + if (!contents.IsValid()) { + RejectPromise(kAllocationFailureImageBitmapRejectionReason); + return; + } + ScheduleAsyncImageBitmapDecoding(std::move(contents)); +} + +void ImageBitmapFactories::ImageBitmapLoader::DidFail(FileErrorCode) { + RejectPromise(kUndecodableImageBitmapRejectionReason); +} + +namespace { +void DecodeImageOnDecoderThread( + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + ArrayBufferContents contents, + ImageDecoder::AlphaOption alpha_option, + ColorBehavior color_behavior, + WTF::CrossThreadOnceFunction< + void(sk_sp<SkImage>, const ImageOrientationEnum)> result_callback) { + const bool data_complete = true; + std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( + SegmentReader::CreateFromSkData( + SkData::MakeWithoutCopy(contents.Data(), contents.DataLength())), + data_complete, alpha_option, ImageDecoder::kDefaultBitDepth, + color_behavior); + sk_sp<SkImage> frame; + ImageOrientationEnum orientation = ImageOrientationEnum::kDefault; + if (decoder) { + orientation = decoder->Orientation().Orientation(); + frame = ImageBitmap::GetSkImageFromDecoder(std::move(decoder)); + } + PostCrossThreadTask(*task_runner, FROM_HERE, + CrossThreadBindOnce(std::move(result_callback), + std::move(frame), orientation)); +} +} // namespace + +void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding( + ArrayBufferContents contents) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + Thread::Current()->GetTaskRunner(); + ImageDecoder::AlphaOption alpha_option = + options_->premultiplyAlpha() != "none" + ? ImageDecoder::AlphaOption::kAlphaPremultiplied + : ImageDecoder::AlphaOption::kAlphaNotPremultiplied; + ColorBehavior color_behavior = options_->colorSpaceConversion() == "none" + ? ColorBehavior::Ignore() + : ColorBehavior::Tag(); + worker_pool::PostTask( + FROM_HERE, + CrossThreadBindOnce( + DecodeImageOnDecoderThread, std::move(task_runner), + std::move(contents), alpha_option, color_behavior, + CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader:: + ResolvePromiseOnOriginalThread, + WrapCrossThreadWeakPersistent(this)))); +} + +void ImageBitmapFactories::ImageBitmapLoader::ResolvePromiseOnOriginalThread( + sk_sp<SkImage> frame, + const ImageOrientationEnum orientation) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!frame) { + RejectPromise(kUndecodableImageBitmapRejectionReason); + return; + } + DCHECK(frame->width()); + DCHECK(frame->height()); + scoped_refptr<StaticBitmapImage> image = + UnacceleratedStaticBitmapImage::Create(std::move(frame), orientation); + + image->SetOriginClean(true); + auto* image_bitmap = + MakeGarbageCollected<ImageBitmap>(image, crop_rect_, options_); + if (image_bitmap && image_bitmap->BitmapImage()) { + resolver_->Resolve(image_bitmap); + } else { + RejectPromise(kAllocationFailureImageBitmapRejectionReason); + return; + } + factory_->DidFinishLoading(this); +} + +void ImageBitmapFactories::ImageBitmapLoader::Trace(Visitor* visitor) const { + ExecutionContextLifecycleObserver::Trace(visitor); + visitor->Trace(factory_); + visitor->Trace(resolver_); + visitor->Trace(options_); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h new file mode 100644 index 00000000000..69f0dedd350 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_ + +#include <memory> + +#include "base/single_thread_task_runner.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_image_bitmap_options.h" +#include "third_party/blink/renderer/bindings/modules/v8/image_bitmap_source.h" +#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_loader.h" +#include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/core/workers/worker_global_scope.h" +#include "third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/bindings/name_client.h" +#include "third_party/blink/renderer/platform/bindings/script_state.h" +#include "third_party/blink/renderer/platform/geometry/int_rect.h" +#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" +#include "third_party/blink/renderer/platform/supplementable.h" +#include "third_party/skia/include/core/SkRefCnt.h" + +class SkImage; + +namespace blink { + +class Blob; +class ExecutionContext; +class ImageBitmapSource; + +class MODULES_EXPORT ImageBitmapFactories final + : public GarbageCollected<ImageBitmapFactories>, + public Supplement<ExecutionContext>, + public NameClient { + public: + static const char kSupplementName[]; + + static ScriptPromise CreateImageBitmap(ScriptState*, + const ImageBitmapSourceUnion&, + const ImageBitmapOptions*, + ExceptionState&); + static ScriptPromise CreateImageBitmap(ScriptState*, + const ImageBitmapSourceUnion&, + int sx, + int sy, + int sw, + int sh, + const ImageBitmapOptions*, + ExceptionState&); + static ScriptPromise CreateImageBitmap(ScriptState*, + ImageBitmapSource*, + base::Optional<IntRect> crop_rect, + const ImageBitmapOptions*, + ExceptionState&); + + // window.createImageBitmap() + static ScriptPromise createImageBitmap( + ScriptState* script_state, + LocalDOMWindow&, + const ImageBitmapSourceUnion& bitmap_source, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + return CreateImageBitmap(script_state, bitmap_source, options, + exception_state); + } + static ScriptPromise createImageBitmap( + ScriptState* script_state, + LocalDOMWindow&, + const ImageBitmapSourceUnion& bitmap_source, + int sx, + int sy, + int sw, + int sh, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + return CreateImageBitmap(script_state, bitmap_source, sx, sy, sw, sh, + options, exception_state); + } + + // worker.createImageBitmap() + static ScriptPromise createImageBitmap( + ScriptState* script_state, + WorkerGlobalScope&, + const ImageBitmapSourceUnion& bitmap_source, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + return CreateImageBitmap(script_state, bitmap_source, options, + exception_state); + } + static ScriptPromise createImageBitmap( + ScriptState* script_state, + WorkerGlobalScope&, + const ImageBitmapSourceUnion& bitmap_source, + int sx, + int sy, + int sw, + int sh, + const ImageBitmapOptions* options, + ExceptionState& exception_state) { + return CreateImageBitmap(script_state, bitmap_source, sx, sy, sw, sh, + options, exception_state); + } + + virtual ~ImageBitmapFactories() = default; + + void Trace(Visitor*) const override; + const char* NameInHeapSnapshot() const override { + return "ImageBitmapLoader"; + } + + private: + class ImageBitmapLoader final : public GarbageCollected<ImageBitmapLoader>, + public ExecutionContextLifecycleObserver, + public FileReaderLoaderClient { + public: + static ImageBitmapLoader* Create(ImageBitmapFactories& factory, + base::Optional<IntRect> crop_rect, + const ImageBitmapOptions* options, + ScriptState* script_state) { + return MakeGarbageCollected<ImageBitmapLoader>(factory, crop_rect, + script_state, options); + } + + ImageBitmapLoader(ImageBitmapFactories&, + base::Optional<IntRect> crop_rect, + ScriptState*, + const ImageBitmapOptions*); + + void LoadBlobAsync(Blob*); + ScriptPromise Promise() { return resolver_->Promise(); } + + void Trace(Visitor*) const override; + + ~ImageBitmapLoader() override; + + private: + SEQUENCE_CHECKER(sequence_checker_); + + enum ImageBitmapRejectionReason { + kUndecodableImageBitmapRejectionReason, + kAllocationFailureImageBitmapRejectionReason, + }; + + void RejectPromise(ImageBitmapRejectionReason); + + void ScheduleAsyncImageBitmapDecoding(ArrayBufferContents); + void ResolvePromiseOnOriginalThread(sk_sp<SkImage>, + const ImageOrientationEnum); + + // ExecutionContextLifecycleObserver + void ContextDestroyed() override; + + // FileReaderLoaderClient + void DidStartLoading() override {} + void DidReceiveData() override {} + void DidFinishLoading() override; + void DidFail(FileErrorCode) override; + + std::unique_ptr<FileReaderLoader> loader_; + Member<ImageBitmapFactories> factory_; + Member<ScriptPromiseResolver> resolver_; + base::Optional<IntRect> crop_rect_; + Member<const ImageBitmapOptions> options_; + }; + + static ImageBitmapFactories& From(ExecutionContext&); + static ScriptPromise CreateImageBitmapFromBlob( + ScriptState*, + ImageBitmapSource*, + base::Optional<IntRect> crop_rect, + const ImageBitmapOptions*); + + void AddLoader(ImageBitmapLoader*); + void DidFinishLoading(ImageBitmapLoader*); + + HeapHashSet<Member<ImageBitmapLoader>> pending_loaders_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_FACTORIES_H_ diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc index 4b94289ec16..6d57d4e62e1 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc @@ -109,7 +109,8 @@ bool ImageBitmapRenderingContextBase::PushFrame() { cc::PaintFlags paint_flags; paint_flags.setBlendMode(SkBlendMode::kSrc); Host()->ResourceProvider()->Canvas()->drawImage( - image->PaintImageForCurrentFrame(), 0, 0, &paint_flags); + image->PaintImageForCurrentFrame(), 0, 0, SkSamplingOptions(), + &paint_flags); scoped_refptr<CanvasResource> resource = Host()->ResourceProvider()->ProduceCanvasResource(); Host()->PushFrame( diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h new file mode 100644 index 00000000000..7f2c0f047d2 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_source_union.h @@ -0,0 +1,17 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_SOURCE_UNION_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_SOURCE_UNION_H_ + +#include "third_party/blink/renderer/bindings/modules/v8/image_bitmap_source.h" + +namespace blink { + +using ImageBitmapSourceUnion = + HTMLImageElementOrSVGImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmapOrOffscreenCanvasOrVideoFrame; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_CANVAS_IMAGEBITMAP_IMAGE_BITMAP_SOURCE_UNION_H_ diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl new file mode 100644 index 00000000000..8cf42d0f1c6 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/window_create_image_bitmap.idl @@ -0,0 +1,24 @@ +// Copyright 2021 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. + +// https://html.spec.whatwg.org/C/#imagebitmapsource +typedef (HTMLImageElement or + SVGImageElement or + HTMLVideoElement or + HTMLCanvasElement or + Blob or + ImageData or + ImageBitmap or + OffscreenCanvas or + VideoFrame) ImageBitmapSource; + +[ + ImplementedAs=ImageBitmapFactories +] partial interface Window { + // https://html.spec.whatwg.org/#windoworworkerglobalscope + [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap( + ImageBitmapSource imageBitmap, optional ImageBitmapOptions options = {}); + [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap( + ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options = {}); +}; diff --git a/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl new file mode 100644 index 00000000000..ee0f155d8bc --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/canvas/imagebitmap/worker_create_image_bitmap.idl @@ -0,0 +1,13 @@ +// Copyright 2021 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. + +[ + ImplementedAs=ImageBitmapFactories +] partial interface WorkerGlobalScope { + // https://html.spec.whatwg.org/#windoworworkerglobalscope + [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap( + ImageBitmapSource imageBitmap, optional ImageBitmapOptions options = {}); + [CallWith=ScriptState, RaisesException] Promise<ImageBitmap> createImageBitmap( + ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options = {}); +}; diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc index 472c8aa6a88..92ffb0ee1e4 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc @@ -148,7 +148,7 @@ TEST_P(OffscreenCanvasTest, CompositorFrameOpacity) { const bool context_alpha = GetParam().alpha; const auto canvas_resource = CanvasResourceSharedBitmap::Create( - offscreen_canvas().Size(), CanvasColorParams(), nullptr /* provider */, + offscreen_canvas().Size(), CanvasResourceParams(), nullptr /* provider */, kLow_SkFilterQuality); EXPECT_TRUE(!!canvas_resource); diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc index eba6275b84f..aa61e529143 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc @@ -136,6 +136,7 @@ void OffscreenCanvasRenderingContext2D::FlushRecording() { return; GetCanvasResourceProvider()->FlushCanvas(); + GetCanvasResourceProvider()->ReleaseLockedImages(); } void OffscreenCanvasRenderingContext2D::FinalizeFrame() { @@ -316,16 +317,9 @@ bool OffscreenCanvasRenderingContext2D::IsPaintable() const { return Host()->ResourceProvider(); } -String OffscreenCanvasRenderingContext2D::ColorSpaceAsString() const { - return CanvasRenderingContext::ColorSpaceAsString(); -} - -CanvasPixelFormat OffscreenCanvasRenderingContext2D::PixelFormat() const { - return ColorParams().PixelFormat(); -} - -CanvasColorParams OffscreenCanvasRenderingContext2D::ColorParams() const { - return CanvasRenderingContext::ColorParams(); +CanvasColorParams OffscreenCanvasRenderingContext2D::GetCanvas2DColorParams() + const { + return CanvasRenderingContext::CanvasRenderingContextColorParams(); } bool OffscreenCanvasRenderingContext2D::WritePixels( @@ -535,6 +529,40 @@ void OffscreenCanvasRenderingContext2D::setFontKerning( ModifiableState().SetFontKerning(kerning, Host()->GetFontSelector()); } +void OffscreenCanvasRenderingContext2D::setFontStretch( + const String& font_stretch) { + if (!GetState().HasRealizedFont()) + setFont(font()); + + String font_stretch_string = font_stretch.LowerASCII(); + FontSelectionValue stretch_vale; + if (font_stretch_string == kUltraCondensedString) + stretch_vale = UltraCondensedWidthValue(); + else if (font_stretch_string == kExtraCondensedString) + stretch_vale = ExtraCondensedWidthValue(); + else if (font_stretch_string == kCondensedString) + stretch_vale = CondensedWidthValue(); + else if (font_stretch_string == kSemiCondensedString) + stretch_vale = SemiCondensedWidthValue(); + else if (font_stretch_string == kNormalStretchString) + stretch_vale = NormalWidthValue(); + else if (font_stretch_string == kSemiExpandedString) + stretch_vale = SemiExpandedWidthValue(); + else if (font_stretch_string == kExpandedString) + stretch_vale = ExpandedWidthValue(); + else if (font_stretch_string == kExtraExpandedString) + stretch_vale = ExtraExpandedWidthValue(); + else if (font_stretch_string == kUltraExpandedString) + stretch_vale = UltraExpandedWidthValue(); + else + return; + + if (GetState().GetFontStretch() == stretch_vale) + return; + + ModifiableState().SetFontStretch(stretch_vale, Host()->GetFontSelector()); +} + void OffscreenCanvasRenderingContext2D::setFontVariantCaps( const String& font_variant_caps_string) { if (!GetState().HasRealizedFont()) diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h index 5d5b0db0f86..42c9ddcb80f 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h @@ -82,6 +82,7 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final void setTextWordSpacing(const double word_spacing); void setTextRendering(const String&); void setFontKerning(const String&); + void setFontStretch(const String&); void setFontVariantCaps(const String&); void fillText(const String& text, double x, double y); @@ -122,6 +123,9 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final void ValidateStateStackWithCanvas(const cc::PaintCanvas*) const final; bool HasAlpha() const final { return CreationAttributes().alpha; } + bool IsDesynchronized() const final { + return CreationAttributes().desynchronized; + } bool isContextLost() const override; ImageBitmap* TransferToImageBitmap(ScriptState*) final; @@ -143,7 +147,7 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final } protected: - CanvasColorParams ColorParams() const override; + CanvasColorParams GetCanvas2DColorParams() const override; bool WritePixels(const SkImageInfo& orig_info, const void* pixels, size_t row_bytes, @@ -167,8 +171,6 @@ class MODULES_EXPORT OffscreenCanvasRenderingContext2D final scoped_refptr<CanvasResource> ProduceCanvasResource(); - String ColorSpaceAsString() const override; - CanvasPixelFormat PixelFormat() const override; SkIRect dirty_rect_for_commit_; bool is_valid_size_ = false; diff --git a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl index 78d97b46178..50727f9025c 100644 --- a/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl +++ b/chromium/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.idl @@ -21,11 +21,22 @@ // transformations (default transform is the identity matrix) void scale(unrestricted double x, unrestricted double y); + [RuntimeEnabled=NewCanvas2DAPI] void scale(unrestricted double x, unrestricted double y, unrestricted double z); void rotate(unrestricted double angle); + [RuntimeEnabled=NewCanvas2DAPI] void rotate3d(unrestricted double angleX, unrestricted double angleY, unrestricted double angleZ); + [RuntimeEnabled=NewCanvas2DAPI] void rotateAxis(unrestricted double axisX, unrestricted double axisY, unrestricted double axisZ, unrestricted double angle); void translate(unrestricted double x, unrestricted double y); + [RuntimeEnabled=NewCanvas2DAPI] void translate(unrestricted double x, unrestricted double y, unrestricted double z); + [RuntimeEnabled=NewCanvas2DAPI] void perspective(unrestricted double length); void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); + [RuntimeEnabled=NewCanvas2DAPI] void transform( + unrestricted double m11, unrestricted double m12, unrestricted double m13, unrestricted double m14, + unrestricted double m21, unrestricted double m22, unrestricted double m23, unrestricted double m24, + unrestricted double m31, unrestricted double m32, unrestricted double m33, unrestricted double m34, + unrestricted double m41, unrestricted double m42, unrestricted double m43, unrestricted double m44 + ); void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f); - [RaisesException] void setTransform(optional DOMMatrix2DInit transform = {}); + [RaisesException] void setTransform(optional DOMMatrixInit transform = {}); DOMMatrix getTransform(); void resetTransform(); @@ -89,7 +100,8 @@ // If OffscreenCanva ships before color managed canvas, this method must remain behind flag. // https://github.com/WICG/canvas-color-space/blob/master/CanvasColorSpaceProposal.md - [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(unsigned long sw, unsigned long sh, ImageDataColorSettings imageDataColorSettings); + [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData getImageData(long sx, long sy, long sw, long sh, ImageDataSettings imageDataSettings); + [RuntimeEnabled=CanvasColorManagement, RaisesException] ImageData createImageData(long sw, long sh, ImageDataSettings imageDataSettings); // Line caps/joins attribute unrestricted double lineWidth; // (default 1) @@ -107,11 +119,12 @@ attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start") attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic") attribute DOMString direction; // "inherit", "rtl", "ltr" (default: "inherit") - [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0) - [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0) [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontKerning; // "auto", "normal", "none" (default: "auto") + [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontStretch; // "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" (default: normal) [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString fontVariantCaps; // "normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps" (default: "normal") + [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textLetterSpacing; // length in pixel (default: 0) [RuntimeEnabled=NewCanvas2DAPI] attribute DOMString textRendering; // "auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision" (default: auto) + [RuntimeEnabled=NewCanvas2DAPI] attribute unrestricted double textWordSpacing; // length in pixel (default: 0) }; OffscreenCanvasRenderingContext2D includes CanvasPath; |