// 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/core/frame/ImageBitmap.h" #include "sky/engine/core/html/ImageData.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 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(ImageData* data, const IntRect& cropRect) : m_imageElement(nullptr) , m_cropRect(cropRect) , m_bitmapOffset(IntPoint()) { IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); OwnPtr 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::create(HTMLImageElement* image, const IntRect& cropRect) { IntRect normalizedCropRect = normalizeRect(cropRect); return adoptRef(new ImageBitmap(image, normalizedCropRect)); } PassRefPtr ImageBitmap::create(ImageData* data, const IntRect& cropRect) { IntRect normalizedCropRect = normalizeRect(cropRect); return adoptRef(new ImageBitmap(data, normalizedCropRect)); } PassRefPtr ImageBitmap::create(ImageBitmap* bitmap, const IntRect& cropRect) { IntRect normalizedCropRect = normalizeRect(cropRect); return adoptRef(new ImageBitmap(bitmap, normalizedCropRect)); } PassRefPtr 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 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; } }