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/image-decoders/ImageDecoder.h" |
10 #include "third_party/skia/include/core/SkSurface.h" | 11 #include "third_party/skia/include/core/SkSurface.h" |
11 #include "wtf/RefPtr.h" | 12 #include "wtf/RefPtr.h" |
12 | 13 |
13 namespace blink { | 14 namespace blink { |
14 | 15 |
15 static const char* imageOrientationFlipY = "flipY"; | 16 static const char* imageOrientationFlipY = "flipY"; |
| 17 static const char* imageBitmapOptionNone = "none"; |
16 | 18 |
| 19 static void parseOptions(const ImageBitmapOptions& options, bool& imageOrientati
onFlipYFlag, bool& premultiplyAlphaEnabledFlag) |
| 20 { |
| 21 if (options.imageOrientation() == imageOrientationFlipY) { |
| 22 imageOrientationFlipYFlag = true; |
| 23 } else { |
| 24 imageOrientationFlipYFlag = false; |
| 25 ASSERT(options.imageOrientation() == imageBitmapOptionNone); |
| 26 } |
| 27 if (options.premultiplyAlpha() == imageBitmapOptionNone) { |
| 28 premultiplyAlphaEnabledFlag = false; |
| 29 } else { |
| 30 premultiplyAlphaEnabledFlag = true; |
| 31 ASSERT(options.premultiplyAlpha() == "default"); |
| 32 } |
| 33 } |
| 34 |
| 35 // The following two functions are helpers used in cropImage |
17 static inline IntRect normalizeRect(const IntRect& rect) | 36 static inline IntRect normalizeRect(const IntRect& rect) |
18 { | 37 { |
19 return IntRect(std::min(rect.x(), rect.maxX()), | 38 return IntRect(std::min(rect.x(), rect.maxX()), |
20 std::min(rect.y(), rect.maxY()), | 39 std::min(rect.y(), rect.maxY()), |
21 std::max(rect.width(), -rect.width()), | 40 std::max(rect.width(), -rect.width()), |
22 std::max(rect.height(), -rect.height())); | 41 std::max(rect.height(), -rect.height())); |
23 } | 42 } |
24 | 43 |
25 // TODO(xidachen): this function needs to be changed later on when implementing
premultiplyAlpha option | 44 static bool frameIsValid(const SkBitmap& frameBitmap) |
| 45 { |
| 46 ASSERT(!frameBitmap.isNull() && !frameBitmap.empty()); |
| 47 return frameBitmap.isImmutable() |
| 48 && frameBitmap.colorType() == kN32_SkColorType; |
| 49 } |
| 50 |
26 static SkImage* flipSkImageVertically(SkImage* input) | 51 static SkImage* flipSkImageVertically(SkImage* input) |
27 { | 52 { |
28 int width = input->width(); | 53 int width = input->width(); |
29 int height = input->height(); | 54 int height = input->height(); |
30 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); | 55 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); |
31 OwnPtr<uint8_t[]> imagePixels = adoptArrayPtr(new uint8_t[width * height * i
nfo.bytesPerPixel()]); | 56 OwnPtr<uint8_t[]> imagePixels = adoptArrayPtr(new uint8_t[width * height * i
nfo.bytesPerPixel()]); |
32 int imageRowBytes = info.bytesPerPixel() * width; | 57 int imageRowBytes = info.bytesPerPixel() * width; |
33 input->readPixels(info, imagePixels.get(), imageRowBytes, 0, 0); | 58 input->readPixels(info, imagePixels.get(), imageRowBytes, 0, 0); |
34 | 59 |
35 for (int i = 0; i < height / 2; i++) { | 60 for (int i = 0; i < height / 2; i++) { |
36 int topFirstElement = i * imageRowBytes; | 61 int topFirstElement = i * imageRowBytes; |
37 int topLastElement = (i + 1) * imageRowBytes; | 62 int topLastElement = (i + 1) * imageRowBytes; |
38 int bottomFirstElement = (height - 1 - i) * imageRowBytes; | 63 int bottomFirstElement = (height - 1 - i) * imageRowBytes; |
39 std::swap_ranges(imagePixels.get() + topFirstElement, imagePixels.get()
+ topLastElement, imagePixels.get() + bottomFirstElement); | 64 std::swap_ranges(imagePixels.get() + topFirstElement, imagePixels.get()
+ topLastElement, imagePixels.get() + bottomFirstElement); |
40 } | 65 } |
41 return SkImage::NewRasterCopy(info, imagePixels.get(), imageRowBytes); | 66 return SkImage::NewRasterCopy(info, imagePixels.get(), imageRowBytes); |
42 } | 67 } |
43 | 68 |
44 static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop
Rect, bool flipYEnabled) | 69 // TODO(xidachen): the part of read an SkImage to a OwnPtr<uint8_t[]> has been u
sed in multiple places, |
| 70 // we should write it as a utility function here. |
| 71 static SkImage* premulSkImageToUnPremul(SkImage* input) |
| 72 { |
| 73 int width = input->width(); |
| 74 int height = input->height(); |
| 75 SkImageInfo info = SkImageInfo::Make(width, height, kN32_SkColorType, kUnpre
mul_SkAlphaType); |
| 76 OwnPtr<uint8_t[]> dstPixels = adoptArrayPtr(new uint8_t[width * height * inf
o.bytesPerPixel()]); |
| 77 size_t dstRowBytes = info.bytesPerPixel() * width; |
| 78 input->readPixels(info, dstPixels.get(), dstRowBytes, 0, 0); |
| 79 return SkImage::NewRasterCopy(info, dstPixels.get(), dstRowBytes); |
| 80 } |
| 81 |
| 82 static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& crop
Rect, bool flipYEnabled, bool premultiplyAlphaEnabled) |
45 { | 83 { |
46 ASSERT(image); | 84 ASSERT(image); |
47 | 85 |
48 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); | 86 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); |
49 const IntRect srcRect = intersection(imgRect, cropRect); | 87 const IntRect srcRect = intersection(imgRect, cropRect); |
50 | 88 |
| 89 RefPtr<SkImage> skiaImage = image->imageForCurrentFrame(); |
| 90 // Attempt to get raw unpremultiplied image data. |
| 91 if (((!premultiplyAlphaEnabled && !skiaImage->isOpaque()) || !skiaImage) &&
image->data()) { |
| 92 // TODO(xidachen): GammaAndColorProfileApplied needs to be changed when
working on color-space conversion |
| 93 OwnPtr<ImageDecoder> decoder(ImageDecoder::create( |
| 94 *(image->data()), ImageDecoder::AlphaNotPremultiplied, |
| 95 ImageDecoder::GammaAndColorProfileApplied)); |
| 96 if (!decoder) |
| 97 return nullptr; |
| 98 decoder->setData(image->data(), true); |
| 99 if (!decoder->frameCount()) |
| 100 return nullptr; |
| 101 ImageFrame* frame = decoder->frameBufferAtIndex(0); |
| 102 if (!frame || frame->status() != ImageFrame::FrameComplete) |
| 103 return nullptr; |
| 104 SkBitmap bitmap = frame->bitmap(); |
| 105 if (!frameIsValid(bitmap)) |
| 106 return nullptr; |
| 107 ASSERT(bitmap.isImmutable()); |
| 108 skiaImage = adoptRef(SkImage::NewFromBitmap(bitmap)); |
| 109 } |
| 110 |
51 if (cropRect == srcRect) { | 111 if (cropRect == srcRect) { |
52 if (flipYEnabled) | 112 if (flipYEnabled) |
53 return StaticBitmapImage::create(adoptRef(flipSkImageVertically(imag
e->imageForCurrentFrame()->newSubset(srcRect)))); | 113 return StaticBitmapImage::create(adoptRef(flipSkImageVertically(skia
Image->newSubset(srcRect)))); |
54 return StaticBitmapImage::create(adoptRef(image->imageForCurrentFrame()-
>newSubset(srcRect))); | 114 return StaticBitmapImage::create(adoptRef(skiaImage->newSubset(srcRect))
); |
55 } | 115 } |
56 | 116 |
57 RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(cropRect.
width(), cropRect.height())); | 117 RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(cropRect.
width(), cropRect.height())); |
58 | 118 // In the case where cropRect doesn't intesect the source image, we return a
premultiplied transparent black SkImage. |
| 119 // If we decide we want to grab meta data from m_image, we have to change th
is. |
59 if (srcRect.isEmpty()) | 120 if (srcRect.isEmpty()) |
60 return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); | 121 return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); |
61 | 122 |
62 SkScalar dstLeft = std::min(0, -cropRect.x()); | 123 SkScalar dstLeft = std::min(0, -cropRect.x()); |
63 SkScalar dstTop = std::min(0, -cropRect.y()); | 124 SkScalar dstTop = std::min(0, -cropRect.y()); |
64 if (cropRect.x() < 0) | 125 if (cropRect.x() < 0) |
65 dstLeft = -cropRect.x(); | 126 dstLeft = -cropRect.x(); |
66 if (cropRect.y() < 0) | 127 if (cropRect.y() < 0) |
67 dstTop = -cropRect.y(); | 128 dstTop = -cropRect.y(); |
68 surface->getCanvas()->drawImage(image->imageForCurrentFrame().get(), dstLeft
, dstTop); | 129 surface->getCanvas()->drawImage(skiaImage.get(), dstLeft, dstTop); |
69 if (flipYEnabled) | 130 if (flipYEnabled) |
70 return StaticBitmapImage::create(adoptRef(flipSkImageVertically(surface-
>newImageSnapshot()))); | 131 skiaImage = adoptRef(flipSkImageVertically(surface->newImageSnapshot()))
; |
71 return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); | 132 else |
| 133 skiaImage = adoptRef(surface->newImageSnapshot()); |
| 134 if (premultiplyAlphaEnabled) |
| 135 return StaticBitmapImage::create(skiaImage); |
| 136 return StaticBitmapImage::create(adoptRef(premulSkImageToUnPremul(skiaImage.
get()))); |
72 } | 137 } |
73 | 138 |
74 ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Docum
ent* document, const ImageBitmapOptions& options) | 139 ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Docum
ent* document, const ImageBitmapOptions& options) |
75 { | 140 { |
76 if (options.imageOrientation() == imageOrientationFlipY) | 141 bool imageOrientationFlipYFlag; |
77 m_image = cropImage(image->cachedImage()->image(), cropRect, true); | 142 bool premultiplyAlphaEnabledFlag; |
78 else | 143 parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag
); |
79 m_image = cropImage(image->cachedImage()->image(), cropRect, false); | 144 |
| 145 m_image = cropImage(image->cachedImage()->image(), cropRect, imageOrientatio
nFlipYFlag, premultiplyAlphaEnabledFlag); |
80 m_image->setOriginClean(!image->wouldTaintOrigin(document->securityOrigin())
); | 146 m_image->setOriginClean(!image->wouldTaintOrigin(document->securityOrigin())
); |
81 } | 147 } |
82 | 148 |
83 ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Docum
ent* document, const ImageBitmapOptions& options) | 149 ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Docum
ent* document, const ImageBitmapOptions& options) |
84 { | 150 { |
85 IntSize playerSize; | 151 IntSize playerSize; |
86 if (video->webMediaPlayer()) | 152 if (video->webMediaPlayer()) |
87 playerSize = video->webMediaPlayer()->naturalSize(); | 153 playerSize = video->webMediaPlayer()->naturalSize(); |
88 | 154 |
89 IntRect videoRect = IntRect(IntPoint(), playerSize); | 155 IntRect videoRect = IntRect(IntPoint(), playerSize); |
90 IntRect srcRect = intersection(cropRect, videoRect); | 156 IntRect srcRect = intersection(cropRect, videoRect); |
91 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(cropRect.size(), NonOpaque,
DoNotInitializeImagePixels); | 157 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(cropRect.size(), NonOpaque,
DoNotInitializeImagePixels); |
92 if (!buffer) | 158 if (!buffer) |
93 return; | 159 return; |
94 | 160 |
95 IntPoint dstPoint = IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRe
ct.y())); | 161 IntPoint dstPoint = IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRe
ct.y())); |
96 video->paintCurrentFrame(buffer->canvas(), IntRect(dstPoint, srcRect.size())
, nullptr); | 162 video->paintCurrentFrame(buffer->canvas(), IntRect(dstPoint, srcRect.size())
, nullptr); |
97 if (options.imageOrientation() == imageOrientationFlipY) | 163 if (options.imageOrientation() == imageOrientationFlipY) |
98 m_image = StaticBitmapImage::create(adoptRef(flipSkImageVertically(buffe
r->newSkImageSnapshot(PreferNoAcceleration).get()))); | 164 m_image = StaticBitmapImage::create(adoptRef(flipSkImageVertically(buffe
r->newSkImageSnapshot(PreferNoAcceleration).get()))); |
99 else | 165 else |
100 m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoA
cceleration)); | 166 m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoA
cceleration)); |
101 m_image->setOriginClean(!video->wouldTaintOrigin(document->securityOrigin())
); | 167 m_image->setOriginClean(!video->wouldTaintOrigin(document->securityOrigin())
); |
102 } | 168 } |
103 | 169 |
104 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect, con
st ImageBitmapOptions& options) | 170 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect, con
st ImageBitmapOptions& options) |
105 { | 171 { |
106 ASSERT(canvas->isPaintable()); | 172 ASSERT(canvas->isPaintable()); |
107 if (options.imageOrientation() == imageOrientationFlipY) | 173 bool imageOrientationFlipYFlag; |
108 m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).
get(), cropRect, true); | 174 bool premultiplyAlphaEnabledFlag; |
109 else | 175 parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag
); |
110 m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).
get(), cropRect, false); | 176 m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).get(
), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag); |
111 m_image->setOriginClean(canvas->originClean()); | 177 m_image->setOriginClean(canvas->originClean()); |
112 } | 178 } |
113 | 179 |
114 ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi
tmapOptions& options) | 180 ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBi
tmapOptions& options) |
115 { | 181 { |
116 IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); | 182 IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); |
117 | 183 |
118 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(cropRect.size(), NonOpaque,
DoNotInitializeImagePixels); | 184 OwnPtr<ImageBuffer> buffer = ImageBuffer::create(cropRect.size(), NonOpaque,
DoNotInitializeImagePixels); |
119 if (!buffer) | 185 if (!buffer) |
120 return; | 186 return; |
(...skipping 10 matching lines...) Expand all Loading... |
131 dstPoint.setY(-cropRect.y()); | 197 dstPoint.setY(-cropRect.y()); |
132 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), srcRe
ct, dstPoint); | 198 buffer->putByteArray(Unmultiplied, data->data()->data(), data->size(), srcRe
ct, dstPoint); |
133 if (options.imageOrientation() == imageOrientationFlipY) | 199 if (options.imageOrientation() == imageOrientationFlipY) |
134 m_image = StaticBitmapImage::create(adoptRef(flipSkImageVertically(buffe
r->newSkImageSnapshot(PreferNoAcceleration).get()))); | 200 m_image = StaticBitmapImage::create(adoptRef(flipSkImageVertically(buffe
r->newSkImageSnapshot(PreferNoAcceleration).get()))); |
135 else | 201 else |
136 m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoA
cceleration)); | 202 m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoA
cceleration)); |
137 } | 203 } |
138 | 204 |
139 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect, const Ima
geBitmapOptions& options) | 205 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect, const Ima
geBitmapOptions& options) |
140 { | 206 { |
141 if (options.imageOrientation() == imageOrientationFlipY) | 207 bool imageOrientationFlipYFlag; |
142 m_image = cropImage(bitmap->bitmapImage(), cropRect, true); | 208 bool premultiplyAlphaEnabledFlag; |
143 else | 209 parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag
); |
144 m_image = cropImage(bitmap->bitmapImage(), cropRect, false); | 210 m_image = cropImage(bitmap->bitmapImage(), cropRect, imageOrientationFlipYFl
ag, true); |
145 m_image->setOriginClean(bitmap->originClean()); | 211 m_image->setOriginClean(bitmap->originClean()); |
146 } | 212 } |
147 | 213 |
148 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cro
pRect, const ImageBitmapOptions& options) | 214 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cro
pRect, const ImageBitmapOptions& options) |
149 { | 215 { |
150 if (options.imageOrientation() == imageOrientationFlipY) | 216 bool imageOrientationFlipYFlag; |
151 m_image = cropImage(image.get(), cropRect, true); | 217 bool premultiplyAlphaEnabledFlag; |
152 else | 218 parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag
); |
153 m_image = cropImage(image.get(), cropRect, false); | 219 m_image = cropImage(image.get(), cropRect, imageOrientationFlipYFlag, premul
tiplyAlphaEnabledFlag); |
154 m_image->setOriginClean(image->originClean()); | 220 m_image->setOriginClean(image->originClean()); |
155 } | 221 } |
156 | 222 |
157 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) | 223 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image) |
158 { | 224 { |
159 m_image = image; | 225 m_image = image; |
160 } | 226 } |
161 | 227 |
162 PassRefPtr<StaticBitmapImage> ImageBitmap::transfer() | 228 PassRefPtr<StaticBitmapImage> ImageBitmap::transfer() |
163 { | 229 { |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 { | 345 { |
280 return FloatSize(width(), height()); | 346 return FloatSize(width(), height()); |
281 } | 347 } |
282 | 348 |
283 DEFINE_TRACE(ImageBitmap) | 349 DEFINE_TRACE(ImageBitmap) |
284 { | 350 { |
285 ImageLoaderClient::trace(visitor); | 351 ImageLoaderClient::trace(visitor); |
286 } | 352 } |
287 | 353 |
288 } // namespace blink | 354 } // namespace blink |
OLD | NEW |