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 3 // found in the LICENSE file. 4 5 #include "config.h" 6 #include "core/frame/ImageBitmap.h" 7 8 #include "core/html/HTMLCanvasElement.h" 9 #include "core/html/HTMLVideoElement.h" 10 #include "core/html/ImageData.h" 11 #include "core/html/canvas/CanvasRenderingContext.h" 12 #include "platform/graphics/BitmapImage.h" 13 #include "platform/graphics/GraphicsContext.h" 14 #include "platform/graphics/ImageBuffer.h" 15 #include "wtf/RefPtr.h" 16 17 using namespace std; 18 19 namespace WebCore { 20 21 static inline IntRect normalizeRect(const IntRect& rect) 22 { 23 return IntRect(min(rect.x(), rect.maxX()), 24 min(rect.y(), rect.maxY()), 25 max(rect.width(), -rect.width()), 26 max(rect.height(), -rect.height())); 27 } 28 29 static inline PassRefPtr<Image> cropImage(Image* image, const IntRect& cropRect) 30 { 31 IntRect intersectRect = intersection(IntRect(IntPoint(), image->size()), cropRect); 32 if (!intersectRect.width() || !intersectRect.height()) 33 return 0; 34 35 SkBitmap cropped; 36 image->nativeImageForCurrentFrame()->bitmap().extractSubset(&cropped, intersectRect); 37 return BitmapImage::create(NativeImageSkia::create(cropped)); 38 } 39 40 ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect) 41 : m_imageElement(image) 42 , m_bitmap(0) 43 , m_cropRect(cropRect) 44 { 45 IntRect srcRect = intersection(cropRect, IntRect(0, 0, image->width(), image->height())); 46 m_bitmapRect = IntRect(IntPoint(max(0, -cropRect.x()), max(0, -cropRect.y())), srcRect.size()); 47 m_bitmapOffset = srcRect.location(); 48 49 if (!srcRect.width() || !srcRect.height()) 50 m_imageElement = 0; 51 else 52 m_imageElement->addClient(this); 53 54 ScriptWrappable::init(this); 55 } 56 57 ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect) 58 : m_imageElement(0) 59 , m_cropRect(cropRect) 60 , m_bitmapOffset(IntPoint()) 61 { 62 IntRect videoRect = IntRect(IntPoint(), video->player()->naturalSize()); 63 IntRect srcRect = intersection(cropRect, videoRect); 64 IntRect dstRect(IntPoint(), srcRect.size()); 65 66 OwnPtr<ImageBuffer> buf = ImageBuffer::create(videoRect.size()); 67 if (!buf) 68 return; 69 GraphicsContext* c = buf->context(); 70 c->clip(dstRect); 71 c->translate(-srcRect.x(), -srcRect.y()); 72 video->paintCurrentFrameInContext(c, videoRect); 73 m_bitmap = buf->copyImage(DontCopyBackingStore); 74 m_bitmapRect = IntRect(IntPoint(max(0, -cropRect.x()), max(0, -cropRect.y())), srcRect.size()); 75 76 ScriptWrappable::init(this); 77 } 78 79 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect) 80 : m_imageElement(0) 81 , m_cropRect(cropRect) 82 , m_bitmapOffset(IntPoint()) 83 { 84 CanvasRenderingContext* sourceContext = canvas->renderingContext(); 85 if (sourceContext && sourceContext->is3d()) 86 sourceContext->paintRenderingResultsToCanvas(); 87 88 IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), canvas->size())); 89 m_bitmapRect = IntRect(IntPoint(max(0, -cropRect.x()), max(0, -cropRect.y())), srcRect.size()); 90 m_bitmap = cropImage(canvas->buffer()->copyImage(CopyBackingStore).get(), cropRect); 91 92 ScriptWrappable::init(this); 93 } 94 95 ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect) 96 : m_imageElement(0) 97 , m_cropRect(cropRect) 98 , m_bitmapOffset(IntPoint()) 99 { 100 IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); 101 102 OwnPtr<ImageBuffer> buf = ImageBuffer::create(data->size()); 103 if (!buf) 104 return; 105 if (srcRect.width() > 0 && srcRect.height() > 0) 106 buf->putByteArray(Premultiplied, data->data(), data->size(), srcRect, IntPoint(min(0, -cropRect.x()), min(0, -cropRect.y()))); 107 108 m_bitmap = buf->copyImage(DontCopyBackingStore); 109 m_bitmapRect = IntRect(IntPoint(max(0, -cropRect.x()), max(0, -cropRect.y())), srcRect.size()); 110 111 ScriptWrappable::init(this); 112 } 113 114 ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect) 115 : m_imageElement(bitmap->imageElement()) 116 , m_bitmap(0) 117 , m_cropRect(cropRect) 118 , m_bitmapOffset(IntPoint()) 119 { 120 IntRect oldBitmapRect = bitmap->bitmapRect(); 121 IntRect srcRect = intersection(cropRect, oldBitmapRect); 122 m_bitmapRect = IntRect(IntPoint(max(0, oldBitmapRect.x() - cropRect.x()), max(0, oldBitmapRect.y() - cropRect.y())), srcRect.size()); 123 124 if (m_imageElement) { 125 m_imageElement->addClient(this); 126 m_bitmapOffset = srcRect.location(); 127 } else if (bitmap->bitmapImage()) { 128 IntRect adjustedCropRect(IntPoint(cropRect.x() -oldBitmapRect.x(), cropRect.y() - oldBitmapRect.y()), cropRect.size()); 129 m_bitmap = cropImage(bitmap->bitmapImage().get(), adjustedCropRect); 130 } 131 132 ScriptWrappable::init(this); 133 } 134 135 ImageBitmap::ImageBitmap(Image* image, const IntRect& cropRect) 136 : m_imageElement(0) 137 , m_cropRect(cropRect) 138 { 139 IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), image->size())); 140 m_bitmap = cropImage(image, cropRect); 141 m_bitmapRect = IntRect(IntPoint(max(0, -cropRect.x()), max(0, -cropRect.y())), srcRect.size()); 142 143 ScriptWrappable::init(this); 144 } 145 146 ImageBitmap::~ImageBitmap() 147 { 148 if (m_imageElement) 149 m_imageElement->removeClient(this); 150 } 151 152 PassRefPtr<ImageBitmap> ImageBitmap::create(HTMLImageElement* image, const IntRect& cropRect) 153 { 154 IntRect normalizedCropRect = normalizeRect(cropRect); 155 return adoptRef(new ImageBitmap(image, normalizedCropRect)); 156 } 157 158 PassRefPtr<ImageBitmap> ImageBitmap::create(HTMLVideoElement* video, const IntRect& cropRect) 159 { 160 IntRect normalizedCropRect = normalizeRect(cropRect); 161 return adoptRef(new ImageBitmap(video, normalizedCropRect)); 162 } 163 164 PassRefPtr<ImageBitmap> ImageBitmap::create(HTMLCanvasElement* canvas, const IntRect& cropRect) 165 { 166 IntRect normalizedCropRect = normalizeRect(cropRect); 167 return adoptRef(new ImageBitmap(canvas, normalizedCropRect)); 168 } 169 170 PassRefPtr<ImageBitmap> ImageBitmap::create(ImageData* data, const IntRect& cropRect) 171 { 172 IntRect normalizedCropRect = normalizeRect(cropRect); 173 return adoptRef(new ImageBitmap(data, normalizedCropRect)); 174 } 175 176 PassRefPtr<ImageBitmap> ImageBitmap::create(ImageBitmap* bitmap, const IntRect& cropRect) 177 { 178 IntRect normalizedCropRect = normalizeRect(cropRect); 179 return adoptRef(new ImageBitmap(bitmap, normalizedCropRect)); 180 } 181 182 PassRefPtr<ImageBitmap> ImageBitmap::create(Image* image, const IntRect& cropRect) 183 { 184 IntRect normalizedCropRect = normalizeRect(cropRect); 185 return adoptRef(new ImageBitmap(image, normalizedCropRect)); 186 } 187 188 void ImageBitmap::notifyImageSourceChanged() 189 { 190 m_bitmap = cropImage(m_imageElement->cachedImage()->image(), m_cropRect); 191 m_bitmapOffset = IntPoint(); 192 m_imageElement = 0; 193 } 194 195 PassRefPtr<Image> ImageBitmap::bitmapImage() const 196 { 197 ASSERT((m_imageElement || m_bitmap || !m_bitmapRect.width() || !m_bitmapRect.height()) && (!m_imageElement || !m_bitmap)); 198 if (m_imageElement) 199 return m_imageElement->cachedImage()->image(); 200 return m_bitmap; 201 } 202 203 } 204