| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/frame/ImageBitmap.h" | 5 #include "core/frame/ImageBitmap.h" |
| 6 | 6 |
| 7 #include "core/html/HTMLCanvasElement.h" | 7 #include "core/html/HTMLCanvasElement.h" |
| 8 #include "core/html/HTMLVideoElement.h" | 8 #include "core/html/HTMLVideoElement.h" |
| 9 #include "core/html/ImageData.h" | 9 #include "core/html/ImageData.h" |
| 10 #include "platform/graphics/skia/SkiaUtils.h" | 10 #include "platform/graphics/skia/SkiaUtils.h" |
| 11 #include "platform/image-decoders/ImageDecoder.h" | 11 #include "platform/image-decoders/ImageDecoder.h" |
| 12 #include "third_party/skia/include/core/SkCanvas.h" | 12 #include "third_party/skia/include/core/SkCanvas.h" |
| 13 #include "third_party/skia/include/core/SkImageInfo.h" |
| 13 #include "third_party/skia/include/core/SkSurface.h" | 14 #include "third_party/skia/include/core/SkSurface.h" |
| 14 #include "wtf/CheckedNumeric.h" | 15 #include "wtf/CheckedNumeric.h" |
| 15 #include "wtf/PtrUtil.h" | 16 #include "wtf/PtrUtil.h" |
| 16 #include "wtf/RefPtr.h" | 17 #include "wtf/RefPtr.h" |
| 17 #include <memory> | 18 #include <memory> |
| 18 | 19 |
| 19 namespace blink { | 20 namespace blink { |
| 20 | 21 |
| 21 static const char* imageOrientationFlipY = "flipY"; | 22 static const char* imageOrientationFlipY = "flipY"; |
| 22 static const char* imageBitmapOptionNone = "none"; | 23 static const char* imageBitmapOptionNone = "none"; |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 struct ParsedOptions { | 27 struct ParsedOptions { |
| 27 bool flipY = false; | 28 bool flipY = false; |
| 28 bool premultiplyAlpha = true; | 29 bool premultiplyAlpha = true; |
| 29 bool shouldScaleInput = false; | 30 bool shouldScaleInput = false; |
| 30 unsigned resizeWidth = 0; | 31 unsigned resizeWidth = 0; |
| 31 unsigned resizeHeight = 0; | 32 unsigned resizeHeight = 0; |
| 32 IntRect cropRect; | 33 IntRect cropRect; |
| 33 SkFilterQuality resizeQuality = kLow_SkFilterQuality; | 34 SkFilterQuality resizeQuality = kLow_SkFilterQuality; |
| 34 // This value should be changed in the future when we support | 35 sk_sp<SkColorSpace> dstColorSpace = nullptr; |
| 35 // createImageBitmap with higher bit depth, in the parseOptions() function. | 36 sk_sp<SkColorSpace> latestColorSpace = nullptr; |
| 36 // For now, it is always 4. | 37 SkColorType dstColorType = kN32_SkColorType; |
| 37 int bytesPerPixel = 4; | 38 SkColorType latestColorType = kN32_SkColorType; |
| 38 }; | 39 }; |
| 39 | 40 |
| 41 ParsedOptions defaultOptions() { |
| 42 return ParsedOptions(); |
| 43 } |
| 44 |
| 40 // The following two functions are helpers used in cropImage | 45 // The following two functions are helpers used in cropImage |
| 41 static inline IntRect normalizeRect(const IntRect& rect) { | 46 static inline IntRect normalizeRect(const IntRect& rect) { |
| 42 return IntRect(std::min(rect.x(), rect.maxX()), | 47 return IntRect(std::min(rect.x(), rect.maxX()), |
| 43 std::min(rect.y(), rect.maxY()), | 48 std::min(rect.y(), rect.maxY()), |
| 44 std::max(rect.width(), -rect.width()), | 49 std::max(rect.width(), -rect.width()), |
| 45 std::max(rect.height(), -rect.height())); | 50 std::max(rect.height(), -rect.height())); |
| 46 } | 51 } |
| 47 | 52 |
| 48 ParsedOptions parseOptions(const ImageBitmapOptions& options, | 53 ParsedOptions parseOptions(const ImageBitmapOptions& options, |
| 49 Optional<IntRect> cropRect, | 54 Optional<IntRect> cropRect, |
| 50 IntSize sourceSize) { | 55 IntSize sourceSize) { |
| 51 ParsedOptions parsedOptions; | 56 ParsedOptions parsedOptions; |
| 52 if (options.imageOrientation() == imageOrientationFlipY) { | 57 if (options.imageOrientation() == imageOrientationFlipY) { |
| 53 parsedOptions.flipY = true; | 58 parsedOptions.flipY = true; |
| 54 } else { | 59 } else { |
| 55 parsedOptions.flipY = false; | 60 parsedOptions.flipY = false; |
| 56 DCHECK(options.imageOrientation() == imageBitmapOptionNone); | 61 DCHECK(options.imageOrientation() == imageBitmapOptionNone); |
| 57 } | 62 } |
| 58 if (options.premultiplyAlpha() == imageBitmapOptionNone) { | 63 if (options.premultiplyAlpha() == imageBitmapOptionNone) { |
| 59 parsedOptions.premultiplyAlpha = false; | 64 parsedOptions.premultiplyAlpha = false; |
| 60 } else { | 65 } else { |
| 61 parsedOptions.premultiplyAlpha = true; | 66 parsedOptions.premultiplyAlpha = true; |
| 62 DCHECK(options.premultiplyAlpha() == "default" || | 67 DCHECK(options.premultiplyAlpha() == "default" || |
| 63 options.premultiplyAlpha() == "premultiply"); | 68 options.premultiplyAlpha() == "premultiply"); |
| 64 } | 69 } |
| 65 | 70 |
| 71 if (options.colorSpaceConversion() != "none") { |
| 72 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() || |
| 73 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) { |
| 74 DCHECK_EQ(options.colorSpaceConversion(), "default"); |
| 75 // TODO(zakerinasab): Replace sRGB with a call to |
| 76 // ImageDecoder::globalTargetColorSpace() when the crash problem on Mac |
| 77 // is fixed. crbug.com/668546. |
| 78 if (RuntimeEnabledFeatures::colorCorrectRenderingDefaultModeEnabled()) { |
| 79 parsedOptions.dstColorSpace = |
| 80 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| 81 parsedOptions.dstColorType = SkColorType::kN32_SkColorType; |
| 82 } |
| 83 } else { |
| 84 if (options.colorSpaceConversion() == "default" || |
| 85 options.colorSpaceConversion() == "srgb") { |
| 86 parsedOptions.dstColorSpace = |
| 87 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
| 88 parsedOptions.dstColorType = SkColorType::kN32_SkColorType; |
| 89 } else if (options.colorSpaceConversion() == "linear-rgb") { |
| 90 parsedOptions.dstColorSpace = |
| 91 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named); |
| 92 parsedOptions.dstColorType = SkColorType::kRGBA_F16_SkColorType; |
| 93 } else { |
| 94 NOTREACHED() |
| 95 << "Invalid ImageBitmap creation attribute colorSpaceConversion: " |
| 96 << options.colorSpaceConversion(); |
| 97 } |
| 98 } |
| 99 } |
| 100 |
| 66 int sourceWidth = sourceSize.width(); | 101 int sourceWidth = sourceSize.width(); |
| 67 int sourceHeight = sourceSize.height(); | 102 int sourceHeight = sourceSize.height(); |
| 68 if (!cropRect) { | 103 if (!cropRect) { |
| 69 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); | 104 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); |
| 70 } else { | 105 } else { |
| 71 parsedOptions.cropRect = normalizeRect(*cropRect); | 106 parsedOptions.cropRect = normalizeRect(*cropRect); |
| 72 } | 107 } |
| 73 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { | 108 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { |
| 74 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); | 109 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); |
| 75 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); | 110 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 100 parsedOptions.resizeQuality = kHigh_SkFilterQuality; | 135 parsedOptions.resizeQuality = kHigh_SkFilterQuality; |
| 101 else if (options.resizeQuality() == "medium") | 136 else if (options.resizeQuality() == "medium") |
| 102 parsedOptions.resizeQuality = kMedium_SkFilterQuality; | 137 parsedOptions.resizeQuality = kMedium_SkFilterQuality; |
| 103 else if (options.resizeQuality() == "pixelated") | 138 else if (options.resizeQuality() == "pixelated") |
| 104 parsedOptions.resizeQuality = kNone_SkFilterQuality; | 139 parsedOptions.resizeQuality = kNone_SkFilterQuality; |
| 105 else | 140 else |
| 106 parsedOptions.resizeQuality = kLow_SkFilterQuality; | 141 parsedOptions.resizeQuality = kLow_SkFilterQuality; |
| 107 return parsedOptions; | 142 return parsedOptions; |
| 108 } | 143 } |
| 109 | 144 |
| 110 bool dstBufferSizeHasOverflow(ParsedOptions options) { | 145 bool dstBufferSizeHasOverflow(const ParsedOptions& options) { |
| 111 CheckedNumeric<unsigned> totalBytes = options.cropRect.width(); | 146 CheckedNumeric<unsigned> totalBytes = options.cropRect.width(); |
| 112 totalBytes *= options.cropRect.height(); | 147 totalBytes *= options.cropRect.height(); |
| 113 totalBytes *= options.bytesPerPixel; | 148 totalBytes *= SkColorTypeBytesPerPixel(options.latestColorType); |
| 114 if (!totalBytes.IsValid()) | 149 if (!totalBytes.IsValid()) |
| 115 return true; | 150 return true; |
| 116 | 151 |
| 117 if (!options.shouldScaleInput) | 152 if (!options.shouldScaleInput) |
| 118 return false; | 153 return false; |
| 119 totalBytes = options.resizeWidth; | 154 totalBytes = options.resizeWidth; |
| 120 totalBytes *= options.resizeHeight; | 155 totalBytes *= options.resizeHeight; |
| 121 totalBytes *= options.bytesPerPixel; | 156 totalBytes *= SkColorTypeBytesPerPixel(options.latestColorType); |
| 122 if (!totalBytes.IsValid()) | 157 if (!totalBytes.IsValid()) |
| 123 return true; | 158 return true; |
| 124 | 159 |
| 125 return false; | 160 return false; |
| 126 } | 161 } |
| 127 | 162 |
| 128 } // namespace | 163 } // namespace |
| 129 | 164 |
| 130 static PassRefPtr<Uint8Array> copySkImageData(SkImage* input, | 165 static PassRefPtr<Uint8Array> copySkImageData(SkImage* input, |
| 131 const SkImageInfo& info) { | 166 const SkImageInfo& info) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 srcAddr + bottomRowStartPosition); | 215 srcAddr + bottomRowStartPosition); |
| 181 } | 216 } |
| 182 } | 217 } |
| 183 } else { | 218 } else { |
| 184 if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle | 219 if (kN32_SkColorType == kBGRA_8888_SkColorType) // needs to swizzle |
| 185 for (unsigned i = 0; i < height * bytesPerRow; i += 4) | 220 for (unsigned i = 0; i < height * bytesPerRow; i += 4) |
| 186 std::swap(srcAddr[i], srcAddr[i + 2]); | 221 std::swap(srcAddr[i], srcAddr[i + 2]); |
| 187 } | 222 } |
| 188 } | 223 } |
| 189 | 224 |
| 190 static sk_sp<SkImage> flipSkImageVertically(SkImage* input, | 225 enum AlphaPremultiplyEnforcement { |
| 191 AlphaDisposition alphaOp) { | 226 EnforceAlphaPremultiply, |
| 227 DontEnforceAlphaPremultiply, |
| 228 }; |
| 229 |
| 230 static sk_sp<SkImage> flipSkImageVertically( |
| 231 SkImage* input, |
| 232 AlphaPremultiplyEnforcement premultiplyEnforcement = |
| 233 DontEnforceAlphaPremultiply, |
| 234 const ParsedOptions& options = defaultOptions()) { |
| 192 unsigned width = static_cast<unsigned>(input->width()); | 235 unsigned width = static_cast<unsigned>(input->width()); |
| 193 unsigned height = static_cast<unsigned>(input->height()); | 236 unsigned height = static_cast<unsigned>(input->height()); |
| 194 SkImageInfo info = SkImageInfo::MakeN32(input->width(), input->height(), | 237 SkAlphaType alphaType = |
| 195 (alphaOp == PremultiplyAlpha) | 238 ((premultiplyEnforcement == EnforceAlphaPremultiply) || |
| 196 ? kPremul_SkAlphaType | 239 options.premultiplyAlpha) |
| 197 : kUnpremul_SkAlphaType); | 240 ? kPremul_SkAlphaType |
| 241 : kUnpremul_SkAlphaType; |
| 242 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), |
| 243 options.latestColorType, alphaType, |
| 244 options.latestColorSpace); |
| 245 |
| 198 unsigned imageRowBytes = width * info.bytesPerPixel(); | 246 unsigned imageRowBytes = width * info.bytesPerPixel(); |
| 199 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info); | 247 RefPtr<Uint8Array> imagePixels = copySkImageData(input, info); |
| 200 if (!imagePixels) | 248 if (!imagePixels) |
| 201 return nullptr; | 249 return nullptr; |
| 202 for (unsigned i = 0; i < height / 2; i++) { | 250 for (unsigned i = 0; i < height / 2; i++) { |
| 203 unsigned topFirstElement = i * imageRowBytes; | 251 unsigned topFirstElement = i * imageRowBytes; |
| 204 unsigned topLastElement = (i + 1) * imageRowBytes; | 252 unsigned topLastElement = (i + 1) * imageRowBytes; |
| 205 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes; | 253 unsigned bottomFirstElement = (height - 1 - i) * imageRowBytes; |
| 206 std::swap_ranges(imagePixels->data() + topFirstElement, | 254 std::swap_ranges(imagePixels->data() + topFirstElement, |
| 207 imagePixels->data() + topLastElement, | 255 imagePixels->data() + topLastElement, |
| 208 imagePixels->data() + bottomFirstElement); | 256 imagePixels->data() + bottomFirstElement); |
| 209 } | 257 } |
| 210 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes); | 258 return newSkImageFromRaster(info, std::move(imagePixels), imageRowBytes); |
| 211 } | 259 } |
| 212 | 260 |
| 213 static sk_sp<SkImage> premulSkImageToUnPremul(SkImage* input) { | 261 static sk_sp<SkImage> premulSkImageToUnPremul( |
| 214 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), | 262 SkImage* input, |
| 215 kN32_SkColorType, kUnpremul_SkAlphaType); | 263 const ParsedOptions& options = defaultOptions()) { |
| 264 SkImageInfo info = SkImageInfo::Make( |
| 265 input->width(), input->height(), options.latestColorType, |
| 266 kUnpremul_SkAlphaType, options.latestColorSpace); |
| 267 |
| 216 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); | 268 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); |
| 217 if (!dstPixels) | 269 if (!dstPixels) |
| 218 return nullptr; | 270 return nullptr; |
| 219 return newSkImageFromRaster( | 271 return newSkImageFromRaster( |
| 220 info, std::move(dstPixels), | 272 info, std::move(dstPixels), |
| 221 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); | 273 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); |
| 222 } | 274 } |
| 223 | 275 |
| 224 static sk_sp<SkImage> unPremulSkImageToPremul(SkImage* input) { | 276 static sk_sp<SkImage> unPremulSkImageToPremul( |
| 225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), | 277 SkImage* input, |
| 226 kN32_SkColorType, kPremul_SkAlphaType); | 278 const ParsedOptions& options = defaultOptions()) { |
| 279 SkImageInfo info = SkImageInfo::Make( |
| 280 input->width(), input->height(), options.latestColorType, |
| 281 kPremul_SkAlphaType, options.latestColorSpace); |
| 282 |
| 227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); | 283 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); |
| 228 if (!dstPixels) | 284 if (!dstPixels) |
| 229 return nullptr; | 285 return nullptr; |
| 230 return newSkImageFromRaster( | 286 return newSkImageFromRaster( |
| 231 info, std::move(dstPixels), | 287 info, std::move(dstPixels), |
| 232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); | 288 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); |
| 233 } | 289 } |
| 234 | 290 |
| 291 // This code is borrowed from third_party/skia/src/codec/SkCodecPriv.h |
| 292 // If you need to change this, please check SkColorSpaceXform::ColorFormat |
| 293 // and SkColorType for proper coverage. |
| 294 static inline SkColorSpaceXform::ColorFormat getXformFormat( |
| 295 SkColorType colorType) { |
| 296 switch (colorType) { |
| 297 case kRGBA_8888_SkColorType: |
| 298 return SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 299 case kBGRA_8888_SkColorType: |
| 300 return SkColorSpaceXform::kBGRA_8888_ColorFormat; |
| 301 case kRGBA_F16_SkColorType: |
| 302 return SkColorSpaceXform::kRGBA_F16_ColorFormat; |
| 303 default: |
| 304 NOTREACHED(); |
| 305 return SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 306 } |
| 307 } |
| 308 |
| 309 static inline void updateLatestColorInformation(ParsedOptions& options) { |
| 310 options.latestColorType = options.dstColorType; |
| 311 options.latestColorSpace = options.dstColorSpace; |
| 312 } |
| 313 |
| 314 // TODO (zakrinasab). Rewrite this when SkImage::readPixels() respectes the |
| 315 // color space of the passed SkImageInfo (crbug.com/skia/6021) and SkImage |
| 316 // exposes SkColorSpace and SkColorType (crbug.com/skia/6022). |
| 317 |
| 318 static void applyColorSpaceConversion(sk_sp<SkImage>& image, |
| 319 ParsedOptions& options) { |
| 320 if (!options.dstColorSpace) |
| 321 return; |
| 322 if (SkColorSpace::Equals(options.latestColorSpace.get(), |
| 323 options.dstColorSpace.get())) |
| 324 return; |
| 325 |
| 326 // If we have the color space information of the source image, we can use |
| 327 // SkColorSpaceXform. Otherwise, we need to draw the image on a canvas and |
| 328 // take a snapshot. |
| 329 if (options.latestColorSpace) { |
| 330 SkImageInfo info = SkImageInfo::Make( |
| 331 image->width(), image->height(), options.latestColorType, |
| 332 image->alphaType(), options.latestColorSpace); |
| 333 size_t size = image->width() * image->height() * info.bytesPerPixel(); |
| 334 std::unique_ptr<uint8_t[]> srcPixels(new uint8_t[size]()); |
| 335 if (!image->readPixels(info, &srcPixels, |
| 336 image->width() * info.bytesPerPixel(), 0, 0)) { |
| 337 return; |
| 338 } |
| 339 |
| 340 // For in-place color correction, bytes per pixel must be equal for source |
| 341 // and destination color spaces. |
| 342 std::unique_ptr<uint8_t[]> dstPixels = nullptr; |
| 343 if (SkColorTypeBytesPerPixel(options.dstColorType) != |
| 344 SkColorTypeBytesPerPixel(options.latestColorType)) { |
| 345 size = image->width() * image->height() * |
| 346 SkColorTypeBytesPerPixel(options.latestColorType); |
| 347 dstPixels = std::unique_ptr<uint8_t[]>(new uint8_t[size]()); |
| 348 } |
| 349 |
| 350 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New( |
| 351 options.latestColorSpace.get(), options.dstColorSpace.get()); |
| 352 xform->apply(getXformFormat(options.dstColorType), |
| 353 dstPixels ? &dstPixels : &srcPixels, |
| 354 getXformFormat(options.latestColorType), &srcPixels, |
| 355 image->width() * image->height(), kUnpremul_SkAlphaType); |
| 356 |
| 357 SkImageInfo dstInfo = |
| 358 SkImageInfo::Make(image->width(), image->height(), options.dstColorType, |
| 359 image->alphaType(), options.dstColorSpace); |
| 360 sk_sp<SkData> data(SkData::MakeWithoutCopy(&dstPixels, size)); |
| 361 sk_sp<SkImage> coloredImage = SkImage::MakeRasterData( |
| 362 dstInfo, data, image->width() * dstInfo.bytesPerPixel()); |
| 363 if (coloredImage) { |
| 364 updateLatestColorInformation(options); |
| 365 image = coloredImage; |
| 366 return; |
| 367 } |
| 368 return; |
| 369 } |
| 370 |
| 371 // Skia does not support drawing to unpremul surfaces/canvases. |
| 372 sk_sp<SkImage> unPremulImage = nullptr; |
| 373 if (image->alphaType() == kUnpremul_SkAlphaType) |
| 374 unPremulImage = unPremulSkImageToPremul(image.get(), options); |
| 375 |
| 376 // If the color space of the source SkImage is null, the following code |
| 377 // does not do any color conversion even thought the new SkImage will be |
| 378 // tagged by the new color space. If this is the case, the following code |
| 379 // will tag a wrong color space to the SkImage. However, this cannot be |
| 380 // addressed here and the code that creates the SkImage must tag the |
| 381 // SkImage with proper color space. |
| 382 SkImageInfo imageInfo = SkImageInfo::Make( |
| 383 image->width(), image->height(), options.dstColorType, |
| 384 unPremulImage ? unPremulImage->alphaType() : image->alphaType(), |
| 385 options.dstColorSpace); |
| 386 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo); |
| 387 surface->getCanvas()->drawImage( |
| 388 unPremulImage ? unPremulImage : sk_sp<SkImage>(image), 0, 0); |
| 389 sk_sp<SkImage> coloredImage = surface->makeImageSnapshot(); |
| 390 updateLatestColorInformation(options); |
| 391 image = coloredImage; |
| 392 return; |
| 393 } |
| 394 |
| 235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( | 395 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( |
| 236 std::unique_ptr<ImageDecoder> decoder) { | 396 std::unique_ptr<ImageDecoder> decoder, |
| 397 SkColorType* decodedColorType, |
| 398 sk_sp<SkColorSpace>* decodedColorSpace, |
| 399 ColorSpaceInfoUpdate colorSpaceInfoUpdate) { |
| 237 if (!decoder->frameCount()) | 400 if (!decoder->frameCount()) |
| 238 return nullptr; | 401 return nullptr; |
| 239 ImageFrame* frame = decoder->frameBufferAtIndex(0); | 402 ImageFrame* frame = decoder->frameBufferAtIndex(0); |
| 240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) | 403 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) |
| 241 return nullptr; | 404 return nullptr; |
| 242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); | 405 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); |
| 243 return frame->finalizePixelsAndGetImage(); | 406 sk_sp<SkImage> image = frame->finalizePixelsAndGetImage(); |
| 407 if (colorSpaceInfoUpdate == UpdateColorSpaceInformation) { |
| 408 *decodedColorType = frame->bitmap().colorType(); |
| 409 *decodedColorSpace = sk_sp<SkColorSpace>(frame->bitmap().colorSpace()); |
| 410 } |
| 411 return image; |
| 244 } | 412 } |
| 245 | 413 |
| 246 bool ImageBitmap::isResizeOptionValid(const ImageBitmapOptions& options, | 414 bool ImageBitmap::isResizeOptionValid(const ImageBitmapOptions& options, |
| 247 ExceptionState& exceptionState) { | 415 ExceptionState& exceptionState) { |
| 248 if ((options.hasResizeWidth() && options.resizeWidth() == 0) || | 416 if ((options.hasResizeWidth() && options.resizeWidth() == 0) || |
| 249 (options.hasResizeHeight() && options.resizeHeight() == 0)) { | 417 (options.hasResizeHeight() && options.resizeHeight() == 0)) { |
| 250 exceptionState.throwDOMException( | 418 exceptionState.throwDOMException( |
| 251 InvalidStateError, | 419 InvalidStateError, |
| 252 "The resizeWidth or/and resizeHeight is equal to 0."); | 420 "The resizeWidth or/and resizeHeight is equal to 0."); |
| 253 return false; | 421 return false; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 265 return false; | 433 return false; |
| 266 } | 434 } |
| 267 return true; | 435 return true; |
| 268 } | 436 } |
| 269 | 437 |
| 270 // The parameter imageFormat indicates whether the first parameter "image" is | 438 // The parameter imageFormat indicates whether the first parameter "image" is |
| 271 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in | 439 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in |
| 272 // premuliplied format For example, if the image is already in unpremultiplied | 440 // premuliplied format For example, if the image is already in unpremultiplied |
| 273 // format and we want the created ImageBitmap in the same format, then we don't | 441 // format and we want the created ImageBitmap in the same format, then we don't |
| 274 // need to use the ImageDecoder to decode the image. | 442 // need to use the ImageDecoder to decode the image. |
| 275 static PassRefPtr<StaticBitmapImage> cropImage( | 443 static PassRefPtr<StaticBitmapImage> cropImageAndApplyColorSpaceConversion( |
| 276 Image* image, | 444 Image* image, |
| 277 const ParsedOptions& parsedOptions, | 445 ParsedOptions& parsedOptions, |
| 278 AlphaDisposition imageFormat, | 446 AlphaDisposition imageFormat, |
| 279 ColorBehavior colorBehavior) { | 447 ColorBehavior colorBehavior) { |
| 280 ASSERT(image); | 448 ASSERT(image); |
| 281 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); | 449 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
| 282 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); | 450 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); |
| 283 | 451 |
| 284 // In the case when cropRect doesn't intersect the source image and it | 452 // In the case when cropRect doesn't intersect the source image and it |
| 285 // requires a umpremul image We immediately return a transparent black image | 453 // requires a umpremul image We immediately return a transparent black image |
| 286 // with cropRect.size() | 454 // with cropRect.size() |
| 287 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { | 455 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 310 !skiaImage) && | 478 !skiaImage) && |
| 311 image->data() && imageFormat == PremultiplyAlpha) || | 479 image->data() && imageFormat == PremultiplyAlpha) || |
| 312 colorBehavior.isIgnore()) { | 480 colorBehavior.isIgnore()) { |
| 313 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( | 481 std::unique_ptr<ImageDecoder> decoder(ImageDecoder::create( |
| 314 image->data(), true, | 482 image->data(), true, |
| 315 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied | 483 parsedOptions.premultiplyAlpha ? ImageDecoder::AlphaPremultiplied |
| 316 : ImageDecoder::AlphaNotPremultiplied, | 484 : ImageDecoder::AlphaNotPremultiplied, |
| 317 colorBehavior)); | 485 colorBehavior)); |
| 318 if (!decoder) | 486 if (!decoder) |
| 319 return nullptr; | 487 return nullptr; |
| 320 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); | 488 skiaImage = ImageBitmap::getSkImageFromDecoder( |
| 489 std::move(decoder), &parsedOptions.latestColorType, |
| 490 &parsedOptions.latestColorSpace, UpdateColorSpaceInformation); |
| 321 if (!skiaImage) | 491 if (!skiaImage) |
| 322 return nullptr; | 492 return nullptr; |
| 323 } | 493 } |
| 324 | 494 |
| 325 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { | 495 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { |
| 326 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); | 496 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); |
| 327 if (parsedOptions.flipY) | 497 if (parsedOptions.dstColorSpace) |
| 498 applyColorSpaceConversion(croppedSkImage, parsedOptions); |
| 499 if (parsedOptions.flipY) { |
| 328 return StaticBitmapImage::create(flipSkImageVertically( | 500 return StaticBitmapImage::create(flipSkImageVertically( |
| 329 croppedSkImage.get(), parsedOptions.premultiplyAlpha | 501 croppedSkImage.get(), DontEnforceAlphaPremultiply, parsedOptions)); |
| 330 ? PremultiplyAlpha | 502 } |
| 331 : DontPremultiplyAlpha)); | |
| 332 // Special case: The first parameter image is unpremul but we need to turn | 503 // Special case: The first parameter image is unpremul but we need to turn |
| 333 // it into premul. | 504 // it into premul. |
| 334 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) | 505 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) |
| 335 return StaticBitmapImage::create( | 506 return StaticBitmapImage::create( |
| 336 unPremulSkImageToPremul(croppedSkImage.get())); | 507 unPremulSkImageToPremul(croppedSkImage.get())); |
| 337 // Call preroll to trigger image decoding. | 508 // Call preroll to trigger image decoding. |
| 338 croppedSkImage->preroll(); | 509 croppedSkImage->preroll(); |
| 339 return StaticBitmapImage::create(std::move(croppedSkImage)); | 510 return StaticBitmapImage::create(std::move(croppedSkImage)); |
| 340 } | 511 } |
| 341 | 512 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 363 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, | 534 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, |
| 364 parsedOptions.resizeHeight); | 535 parsedOptions.resizeHeight); |
| 365 SkPaint paint; | 536 SkPaint paint; |
| 366 paint.setFilterQuality(parsedOptions.resizeQuality); | 537 paint.setFilterQuality(parsedOptions.resizeQuality); |
| 367 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, | 538 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, |
| 368 &paint); | 539 &paint); |
| 369 } else { | 540 } else { |
| 370 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); | 541 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); |
| 371 } | 542 } |
| 372 skiaImage = surface->makeImageSnapshot(); | 543 skiaImage = surface->makeImageSnapshot(); |
| 544 if (parsedOptions.dstColorSpace) |
| 545 applyColorSpaceConversion(skiaImage, parsedOptions); |
| 373 | 546 |
| 374 if (parsedOptions.premultiplyAlpha) { | 547 if (parsedOptions.premultiplyAlpha) { |
| 375 if (imageFormat == DontPremultiplyAlpha) | 548 if (imageFormat == DontPremultiplyAlpha) |
| 376 return StaticBitmapImage::create( | 549 return StaticBitmapImage::create( |
| 377 unPremulSkImageToPremul(skiaImage.get())); | 550 unPremulSkImageToPremul(skiaImage.get())); |
| 378 return StaticBitmapImage::create(std::move(skiaImage)); | 551 return StaticBitmapImage::create(std::move(skiaImage)); |
| 379 } | 552 } |
| 380 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); | 553 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); |
| 381 } | 554 } |
| 382 | 555 |
| 383 ImageBitmap::ImageBitmap(HTMLImageElement* image, | 556 ImageBitmap::ImageBitmap(HTMLImageElement* image, |
| 384 Optional<IntRect> cropRect, | 557 Optional<IntRect> cropRect, |
| 385 Document* document, | 558 Document* document, |
| 386 const ImageBitmapOptions& options) { | 559 const ImageBitmapOptions& options) { |
| 387 RefPtr<Image> input = image->cachedImage()->getImage(); | 560 RefPtr<Image> input = image->cachedImage()->getImage(); |
| 388 ParsedOptions parsedOptions = | 561 ParsedOptions parsedOptions = |
| 389 parseOptions(options, cropRect, image->bitmapSourceSize()); | 562 parseOptions(options, cropRect, image->bitmapSourceSize()); |
| 390 if (dstBufferSizeHasOverflow(parsedOptions)) | 563 if (dstBufferSizeHasOverflow(parsedOptions)) |
| 391 return; | 564 return; |
| 392 | 565 |
| 393 if (options.colorSpaceConversion() == "none") { | 566 if (options.colorSpaceConversion() == "none") { |
| 394 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 567 m_image = cropImageAndApplyColorSpaceConversion( |
| 395 ColorBehavior::ignore()); | 568 input.get(), parsedOptions, PremultiplyAlpha, ColorBehavior::ignore()); |
| 396 } else { | 569 } else { |
| 397 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 570 m_image = cropImageAndApplyColorSpaceConversion( |
| 398 ColorBehavior::transformToGlobalTarget()); | 571 input.get(), parsedOptions, PremultiplyAlpha, |
| 572 ColorBehavior::transformToGlobalTarget()); |
| 399 } | 573 } |
| 574 |
| 400 if (!m_image) | 575 if (!m_image) |
| 401 return; | 576 return; |
| 402 // In the case where the source image is lazy-decoded, m_image may not be in | 577 // In the case where the source image is lazy-decoded, m_image may not be in |
| 403 // a decoded state, we trigger it here. | 578 // a decoded state, we trigger it here. |
| 404 // TODO(ccameron): Canvas should operate in sRGB and not display space. | 579 // TODO(ccameron): Canvas should operate in sRGB and not display space. |
| 405 // https://crbug.com/667431 | 580 // https://crbug.com/667431 |
| 406 sk_sp<SkImage> skImage = | 581 sk_sp<SkImage> skImage = |
| 407 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()); | 582 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()); |
| 408 SkPixmap pixmap; | 583 SkPixmap pixmap; |
| 409 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { | 584 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { |
| 410 sk_sp<SkSurface> surface = | 585 SkImageInfo imageInfo = SkImageInfo::Make( |
| 411 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); | 586 skImage->width(), skImage->height(), parsedOptions.dstColorType, |
| 587 kPremul_SkAlphaType, parsedOptions.dstColorSpace); |
| 588 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo); |
| 412 surface->getCanvas()->drawImage(skImage, 0, 0); | 589 surface->getCanvas()->drawImage(skImage, 0, 0); |
| 413 m_image = StaticBitmapImage::create(surface->makeImageSnapshot()); | 590 m_image = StaticBitmapImage::create(surface->makeImageSnapshot()); |
| 414 } | 591 } |
| 415 if (!m_image) | 592 if (!m_image) |
| 416 return; | 593 return; |
| 417 m_image->setOriginClean( | 594 m_image->setOriginClean( |
| 418 !image->wouldTaintOrigin(document->getSecurityOrigin())); | 595 !image->wouldTaintOrigin(document->getSecurityOrigin())); |
| 419 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 596 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 420 } | 597 } |
| 421 | 598 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 ParsedOptions parsedOptions = | 661 ParsedOptions parsedOptions = |
| 485 parseOptions(options, cropRect, IntSize(input->width(), input->height())); | 662 parseOptions(options, cropRect, IntSize(input->width(), input->height())); |
| 486 if (dstBufferSizeHasOverflow(parsedOptions)) | 663 if (dstBufferSizeHasOverflow(parsedOptions)) |
| 487 return; | 664 return; |
| 488 | 665 |
| 489 bool isPremultiplyAlphaReverted = false; | 666 bool isPremultiplyAlphaReverted = false; |
| 490 if (!parsedOptions.premultiplyAlpha) { | 667 if (!parsedOptions.premultiplyAlpha) { |
| 491 parsedOptions.premultiplyAlpha = true; | 668 parsedOptions.premultiplyAlpha = true; |
| 492 isPremultiplyAlphaReverted = true; | 669 isPremultiplyAlphaReverted = true; |
| 493 } | 670 } |
| 494 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 671 m_image = cropImageAndApplyColorSpaceConversion( |
| 495 ColorBehavior::transformToGlobalTarget()); | 672 input.get(), parsedOptions, PremultiplyAlpha, |
| 673 ColorBehavior::transformToGlobalTarget()); |
| 496 if (!m_image) | 674 if (!m_image) |
| 497 return; | 675 return; |
| 498 if (isPremultiplyAlphaReverted) { | 676 if (isPremultiplyAlphaReverted) { |
| 499 parsedOptions.premultiplyAlpha = false; | 677 parsedOptions.premultiplyAlpha = false; |
| 500 // TODO(ccameron): Canvas should operate in sRGB and not display space. | 678 // TODO(ccameron): Canvas should operate in sRGB and not display space. |
| 501 // https://crbug.com/667431 | 679 // https://crbug.com/667431 |
| 502 m_image = StaticBitmapImage::create(premulSkImageToUnPremul( | 680 m_image = StaticBitmapImage::create(premulSkImageToUnPremul( |
| 503 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()) | 681 m_image->imageForCurrentFrame(ColorBehavior::transformToGlobalTarget()) |
| 504 .get())); | 682 .get())); |
| 505 } | 683 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 671 std::min(0, -parsedOptions.cropRect.y())); | 849 std::min(0, -parsedOptions.cropRect.y())); |
| 672 if (parsedOptions.cropRect.x() < 0) | 850 if (parsedOptions.cropRect.x() < 0) |
| 673 dstPoint.setX(-parsedOptions.cropRect.x()); | 851 dstPoint.setX(-parsedOptions.cropRect.x()); |
| 674 if (parsedOptions.cropRect.y() < 0) | 852 if (parsedOptions.cropRect.y() < 0) |
| 675 dstPoint.setY(-parsedOptions.cropRect.y()); | 853 dstPoint.setY(-parsedOptions.cropRect.y()); |
| 676 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), | 854 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), |
| 677 srcRect, dstPoint); | 855 srcRect, dstPoint); |
| 678 sk_sp<SkImage> skImage = | 856 sk_sp<SkImage> skImage = |
| 679 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); | 857 buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown); |
| 680 if (parsedOptions.flipY) | 858 if (parsedOptions.flipY) |
| 681 skImage = flipSkImageVertically(skImage.get(), PremultiplyAlpha); | 859 skImage = flipSkImageVertically(skImage.get(), EnforceAlphaPremultiply); |
| 682 if (!skImage) | 860 if (!skImage) |
| 683 return; | 861 return; |
| 684 if (parsedOptions.shouldScaleInput) { | 862 if (parsedOptions.shouldScaleInput) { |
| 685 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( | 863 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( |
| 686 parsedOptions.resizeWidth, parsedOptions.resizeHeight); | 864 parsedOptions.resizeWidth, parsedOptions.resizeHeight); |
| 687 if (!surface) | 865 if (!surface) |
| 688 return; | 866 return; |
| 689 SkPaint paint; | 867 SkPaint paint; |
| 690 paint.setFilterQuality(parsedOptions.resizeQuality); | 868 paint.setFilterQuality(parsedOptions.resizeQuality); |
| 691 SkRect dstDrawRect = | 869 SkRect dstDrawRect = |
| 692 SkRect::MakeWH(parsedOptions.resizeWidth, parsedOptions.resizeHeight); | 870 SkRect::MakeWH(parsedOptions.resizeWidth, parsedOptions.resizeHeight); |
| 693 surface->getCanvas()->drawImageRect(skImage, dstDrawRect, &paint); | 871 surface->getCanvas()->drawImageRect(skImage, dstDrawRect, &paint); |
| 694 skImage = surface->makeImageSnapshot(); | 872 skImage = surface->makeImageSnapshot(); |
| 695 } | 873 } |
| 696 m_image = StaticBitmapImage::create(std::move(skImage)); | 874 m_image = StaticBitmapImage::create(std::move(skImage)); |
| 697 } | 875 } |
| 698 | 876 |
| 699 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, | 877 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, |
| 700 Optional<IntRect> cropRect, | 878 Optional<IntRect> cropRect, |
| 701 const ImageBitmapOptions& options) { | 879 const ImageBitmapOptions& options) { |
| 702 RefPtr<Image> input = bitmap->bitmapImage(); | 880 RefPtr<Image> input = bitmap->bitmapImage(); |
| 703 if (!input) | 881 if (!input) |
| 704 return; | 882 return; |
| 705 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); | 883 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); |
| 706 if (dstBufferSizeHasOverflow(parsedOptions)) | 884 if (dstBufferSizeHasOverflow(parsedOptions)) |
| 707 return; | 885 return; |
| 708 | 886 |
| 709 m_image = cropImage( | 887 m_image = cropImageAndApplyColorSpaceConversion( |
| 710 input.get(), parsedOptions, | 888 input.get(), parsedOptions, |
| 711 bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha, | 889 bitmap->isPremultiplied() ? PremultiplyAlpha : DontPremultiplyAlpha, |
| 712 ColorBehavior::transformToGlobalTarget()); | 890 ColorBehavior::transformToGlobalTarget()); |
| 713 if (!m_image) | 891 if (!m_image) |
| 714 return; | 892 return; |
| 715 m_image->setOriginClean(bitmap->originClean()); | 893 m_image->setOriginClean(bitmap->originClean()); |
| 716 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 894 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 717 } | 895 } |
| 718 | 896 |
| 719 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, | 897 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, |
| 720 Optional<IntRect> cropRect, | 898 Optional<IntRect> cropRect, |
| 721 const ImageBitmapOptions& options) { | 899 const ImageBitmapOptions& options) { |
| 722 bool originClean = image->originClean(); | 900 bool originClean = image->originClean(); |
| 723 RefPtr<Image> input = image; | 901 RefPtr<Image> input = image; |
| 724 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); | 902 ParsedOptions parsedOptions = parseOptions(options, cropRect, input->size()); |
| 725 if (dstBufferSizeHasOverflow(parsedOptions)) | 903 if (dstBufferSizeHasOverflow(parsedOptions)) |
| 726 return; | 904 return; |
| 727 | 905 |
| 728 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, | 906 m_image = cropImageAndApplyColorSpaceConversion( |
| 729 ColorBehavior::transformToGlobalTarget()); | 907 input.get(), parsedOptions, PremultiplyAlpha, |
| 908 ColorBehavior::transformToGlobalTarget()); |
| 730 if (!m_image) | 909 if (!m_image) |
| 731 return; | 910 return; |
| 732 | 911 |
| 733 m_image->setOriginClean(originClean); | 912 m_image->setOriginClean(originClean); |
| 734 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); | 913 m_image->setPremultiplied(parsedOptions.premultiplyAlpha); |
| 735 } | 914 } |
| 736 | 915 |
| 737 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) { | 916 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) { |
| 738 m_image = image; | 917 m_image = image; |
| 739 } | 918 } |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 879 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, | 1058 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, |
| 880 FloatRect* dstRect) const {} | 1059 FloatRect* dstRect) const {} |
| 881 | 1060 |
| 882 FloatSize ImageBitmap::elementSize(const FloatSize&) const { | 1061 FloatSize ImageBitmap::elementSize(const FloatSize&) const { |
| 883 return FloatSize(width(), height()); | 1062 return FloatSize(width(), height()); |
| 884 } | 1063 } |
| 885 | 1064 |
| 886 DEFINE_TRACE(ImageBitmap) {} | 1065 DEFINE_TRACE(ImageBitmap) {} |
| 887 | 1066 |
| 888 } // namespace blink | 1067 } // namespace blink |
| OLD | NEW |