| // Copyright 2013 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 "sky/engine/config.h" | 
 | #include "sky/engine/core/frame/ImageBitmap.h" | 
 |  | 
 | #include "sky/engine/core/html/HTMLCanvasElement.h" | 
 | #include "sky/engine/core/html/ImageData.h" | 
 | #include "sky/engine/core/html/canvas/CanvasRenderingContext.h" | 
 | #include "sky/engine/platform/graphics/BitmapImage.h" | 
 | #include "sky/engine/platform/graphics/GraphicsContext.h" | 
 | #include "sky/engine/platform/graphics/ImageBuffer.h" | 
 | #include "sky/engine/wtf/RefPtr.h" | 
 |  | 
 | namespace blink { | 
 |  | 
 | static inline IntRect normalizeRect(const IntRect& rect) | 
 | { | 
 |     return IntRect(std::min(rect.x(), rect.maxX()), | 
 |         std::min(rect.y(), rect.maxY()), | 
 |         std::max(rect.width(), -rect.width()), | 
 |         std::max(rect.height(), -rect.height())); | 
 | } | 
 |  | 
 | static inline PassRefPtr<Image> cropImage(Image* image, const IntRect& cropRect) | 
 | { | 
 |     IntRect intersectRect = intersection(IntRect(IntPoint(), image->size()), cropRect); | 
 |     if (!intersectRect.width() || !intersectRect.height()) | 
 |         return nullptr; | 
 |  | 
 |     SkBitmap cropped; | 
 |     image->nativeImageForCurrentFrame()->bitmap().extractSubset(&cropped, intersectRect); | 
 |     return BitmapImage::create(NativeImageSkia::create(cropped)); | 
 | } | 
 |  | 
 | ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect) | 
 |     : m_imageElement(image) | 
 |     , m_bitmap(nullptr) | 
 |     , m_cropRect(cropRect) | 
 | { | 
 |     IntRect srcRect = intersection(cropRect, IntRect(0, 0, image->width(), image->height())); | 
 |     m_bitmapRect = IntRect(IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRect.y())), srcRect.size()); | 
 |     m_bitmapOffset = srcRect.location(); | 
 |  | 
 |     if (!srcRect.width() || !srcRect.height()) | 
 |         m_imageElement = nullptr; | 
 |     else | 
 |         m_imageElement->addClient(this); | 
 |  | 
 | } | 
 |  | 
 | ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect) | 
 |     : m_imageElement(nullptr) | 
 |     , m_cropRect(cropRect) | 
 |     , m_bitmapOffset(IntPoint()) | 
 | { | 
 |     CanvasRenderingContext* sourceContext = canvas->renderingContext(); | 
 |     if (sourceContext && sourceContext->is3d()) | 
 |         sourceContext->paintRenderingResultsToCanvas(); | 
 |  | 
 |     IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), canvas->size())); | 
 |     m_bitmapRect = IntRect(IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRect.y())), srcRect.size()); | 
 |     m_bitmap = cropImage(canvas->buffer()->copyImage(CopyBackingStore).get(), cropRect); | 
 | } | 
 |  | 
 | ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect) | 
 |     : m_imageElement(nullptr) | 
 |     , m_cropRect(cropRect) | 
 |     , m_bitmapOffset(IntPoint()) | 
 | { | 
 |     IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); | 
 |  | 
 |     OwnPtr<ImageBuffer> buf = ImageBuffer::create(data->size()); | 
 |     if (!buf) | 
 |         return; | 
 |     if (srcRect.width() > 0 && srcRect.height() > 0) | 
 |         buf->putByteArray(Premultiplied, data->data(), data->size(), srcRect, IntPoint(std::min(0, -cropRect.x()), std::min(0, -cropRect.y()))); | 
 |  | 
 |     m_bitmap = buf->copyImage(DontCopyBackingStore); | 
 |     m_bitmapRect = IntRect(IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRect.y())),  srcRect.size()); | 
 | } | 
 |  | 
 | ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect) | 
 |     : m_imageElement(bitmap->imageElement()) | 
 |     , m_bitmap(nullptr) | 
 |     , m_cropRect(cropRect) | 
 |     , m_bitmapOffset(IntPoint()) | 
 | { | 
 |     IntRect oldBitmapRect = bitmap->bitmapRect(); | 
 |     IntRect srcRect = intersection(cropRect, oldBitmapRect); | 
 |     m_bitmapRect = IntRect(IntPoint(std::max(0, oldBitmapRect.x() - cropRect.x()), std::max(0, oldBitmapRect.y() - cropRect.y())), srcRect.size()); | 
 |  | 
 |     if (m_imageElement) { | 
 |         m_imageElement->addClient(this); | 
 |         m_bitmapOffset = srcRect.location(); | 
 |     } else if (bitmap->bitmapImage()) { | 
 |         IntRect adjustedCropRect(IntPoint(cropRect.x() -oldBitmapRect.x(), cropRect.y() - oldBitmapRect.y()), cropRect.size()); | 
 |         m_bitmap = cropImage(bitmap->bitmapImage().get(), adjustedCropRect); | 
 |     } | 
 | } | 
 |  | 
 | ImageBitmap::ImageBitmap(Image* image, const IntRect& cropRect) | 
 |     : m_imageElement(nullptr) | 
 |     , m_cropRect(cropRect) | 
 | { | 
 |     IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), image->size())); | 
 |     m_bitmap = cropImage(image, cropRect); | 
 |     m_bitmapRect = IntRect(IntPoint(std::max(0, -cropRect.x()), std::max(0, -cropRect.y())),  srcRect.size()); | 
 | } | 
 |  | 
 | ImageBitmap::~ImageBitmap() | 
 | { | 
 | #if !ENABLE(OILPAN) | 
 |     if (m_imageElement) | 
 |         m_imageElement->removeClient(this); | 
 | #endif | 
 | } | 
 |  | 
 | PassRefPtr<ImageBitmap> ImageBitmap::create(HTMLImageElement* image, const IntRect& cropRect) | 
 | { | 
 |     IntRect normalizedCropRect = normalizeRect(cropRect); | 
 |     return adoptRef(new ImageBitmap(image, normalizedCropRect)); | 
 | } | 
 |  | 
 | PassRefPtr<ImageBitmap> ImageBitmap::create(HTMLCanvasElement* canvas, const IntRect& cropRect) | 
 | { | 
 |     IntRect normalizedCropRect = normalizeRect(cropRect); | 
 |     return adoptRef(new ImageBitmap(canvas, normalizedCropRect)); | 
 | } | 
 |  | 
 | PassRefPtr<ImageBitmap> ImageBitmap::create(ImageData* data, const IntRect& cropRect) | 
 | { | 
 |     IntRect normalizedCropRect = normalizeRect(cropRect); | 
 |     return adoptRef(new ImageBitmap(data, normalizedCropRect)); | 
 | } | 
 |  | 
 | PassRefPtr<ImageBitmap> ImageBitmap::create(ImageBitmap* bitmap, const IntRect& cropRect) | 
 | { | 
 |     IntRect normalizedCropRect = normalizeRect(cropRect); | 
 |     return adoptRef(new ImageBitmap(bitmap, normalizedCropRect)); | 
 | } | 
 |  | 
 | PassRefPtr<ImageBitmap> ImageBitmap::create(Image* image, const IntRect& cropRect) | 
 | { | 
 |     IntRect normalizedCropRect = normalizeRect(cropRect); | 
 |     return adoptRef(new ImageBitmap(image, normalizedCropRect)); | 
 | } | 
 |  | 
 | void ImageBitmap::notifyImageSourceChanged() | 
 | { | 
 |     m_bitmap = cropImage(m_imageElement->cachedImage()->image(), m_cropRect); | 
 |     m_bitmapOffset = IntPoint(); | 
 |     m_imageElement = nullptr; | 
 | } | 
 |  | 
 | PassRefPtr<Image> ImageBitmap::bitmapImage() const | 
 | { | 
 |     ASSERT((m_imageElement || m_bitmap || !m_bitmapRect.width() || !m_bitmapRect.height()) && (!m_imageElement || !m_bitmap)); | 
 |     if (m_imageElement) | 
 |         return m_imageElement->cachedImage()->image(); | 
 |     return m_bitmap; | 
 | } | 
 |  | 
 | PassRefPtr<Image> ImageBitmap::getSourceImageForCanvas(SourceImageMode, SourceImageStatus* status) const | 
 | { | 
 |     *status = NormalSourceImageStatus; | 
 |     return bitmapImage(); | 
 | } | 
 |  | 
 | void ImageBitmap::adjustDrawRects(FloatRect* srcRect, FloatRect* dstRect) const | 
 | { | 
 |     FloatRect intersectRect = intersection(m_bitmapRect, *srcRect); | 
 |     FloatRect newSrcRect = intersectRect; | 
 |     newSrcRect.move(m_bitmapOffset - m_bitmapRect.location()); | 
 |     FloatRect newDstRect(FloatPoint(intersectRect.location() - srcRect->location()), m_bitmapRect.size()); | 
 |     newDstRect.scale(dstRect->width() / srcRect->width() * intersectRect.width() / m_bitmapRect.width(), | 
 |         dstRect->height() / srcRect->height() * intersectRect.height() / m_bitmapRect.height()); | 
 |     newDstRect.moveBy(dstRect->location()); | 
 |     *srcRect = newSrcRect; | 
 |     *dstRect = newDstRect; | 
 | } | 
 |  | 
 | FloatSize ImageBitmap::sourceSize() const | 
 | { | 
 |     return FloatSize(width(), height()); | 
 | } | 
 |  | 
 | } |