summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/ImageBackingStore.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/ImageBackingStore.h')
-rw-r--r--Source/WebCore/platform/graphics/ImageBackingStore.h224
1 files changed, 224 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/ImageBackingStore.h b/Source/WebCore/platform/graphics/ImageBackingStore.h
new file mode 100644
index 000000000..4c59f6842
--- /dev/null
+++ b/Source/WebCore/platform/graphics/ImageBackingStore.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Color.h"
+#include "IntRect.h"
+#include "IntSize.h"
+#include "NativeImage.h"
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+class ImageBackingStore {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static std::unique_ptr<ImageBackingStore> create(const IntSize& size, bool premultiplyAlpha = true)
+ {
+ return std::unique_ptr<ImageBackingStore>(new ImageBackingStore(size, premultiplyAlpha));
+ }
+
+ static std::unique_ptr<ImageBackingStore> create(const ImageBackingStore& other)
+ {
+ return std::unique_ptr<ImageBackingStore>(new ImageBackingStore(other));
+ }
+
+ NativeImagePtr image() const;
+
+ bool setSize(const IntSize& size)
+ {
+ if (size.isEmpty())
+ return false;
+
+ Vector<char> buffer;
+ size_t bufferSize = size.area().unsafeGet() * sizeof(RGBA32);
+
+ if (!buffer.tryReserveCapacity(bufferSize))
+ return false;
+
+ buffer.resize(bufferSize);
+ m_pixels = SharedBuffer::adoptVector(buffer);
+ m_pixelsPtr = reinterpret_cast<RGBA32*>(const_cast<char*>(m_pixels->data()));
+ m_size = size;
+ m_frameRect = IntRect(IntPoint(), m_size);
+ clear();
+ return true;
+ }
+
+ void setFrameRect(const IntRect& frameRect)
+ {
+ ASSERT(!m_size.isEmpty());
+ ASSERT(inBounds(frameRect));
+ m_frameRect = frameRect;
+ }
+
+ const IntSize& size() const { return m_size; }
+ const IntRect& frameRect() const { return m_frameRect; }
+
+ void clear()
+ {
+ memset(m_pixelsPtr, 0, (m_size.area() * sizeof(RGBA32)).unsafeGet());
+ }
+
+ void clearRect(const IntRect& rect)
+ {
+ if (rect.isEmpty() || !inBounds(rect))
+ return;
+
+ size_t rowBytes = rect.width() * sizeof(RGBA32);
+ RGBA32* start = pixelAt(rect.x(), rect.y());
+ for (int i = 0; i < rect.height(); ++i) {
+ memset(start, 0, rowBytes);
+ start += m_size.width();
+ }
+ }
+
+ void fillRect(const IntRect &rect, unsigned r, unsigned g, unsigned b, unsigned a)
+ {
+ if (rect.isEmpty() || !inBounds(rect))
+ return;
+
+ RGBA32* start = pixelAt(rect.x(), rect.y());
+ RGBA32 pixelValue = this->pixelValue(r, g, b, a);
+ for (int i = 0; i < rect.height(); ++i) {
+ for (int j = 0; j < rect.width(); ++j)
+ start[j] = pixelValue;
+ start += m_size.width();
+ }
+ }
+
+ void repeatFirstRow(const IntRect& rect)
+ {
+ if (rect.isEmpty() || !inBounds(rect))
+ return;
+
+ size_t rowBytes = rect.width() * sizeof(RGBA32);
+ RGBA32* src = pixelAt(rect.x(), rect.y());
+ RGBA32* dest = src + m_size.width();
+ for (int i = 1; i < rect.height(); ++i) {
+ memcpy(dest, src, rowBytes);
+ dest += m_size.width();
+ }
+ }
+
+ RGBA32* pixelAt(int x, int y) const
+ {
+ ASSERT(inBounds(IntPoint(x, y)));
+ return m_pixelsPtr + y * m_size.width() + x;
+ }
+
+ void setPixel(RGBA32* dest, unsigned r, unsigned g, unsigned b, unsigned a)
+ {
+ ASSERT(dest);
+ *dest = pixelValue(r, g, b, a);
+ }
+
+ void setPixel(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a)
+ {
+ setPixel(pixelAt(x, y), r, g, b, a);
+ }
+
+#if ENABLE(APNG)
+ void blendPixel(RGBA32* dest, unsigned r, unsigned g, unsigned b, unsigned a)
+ {
+ if (!a)
+ return;
+
+ if (a >= 255 || !alphaChannel(*dest)) {
+ setPixel(dest, r, g, b, a);
+ return;
+ }
+
+ if (!m_premultiplyAlpha)
+ *dest = makePremultipliedRGBA(redChannel(*dest), greenChannel(*dest), blueChannel(*dest), alphaChannel(*dest), false);
+
+ unsigned d = 255 - a;
+
+ r = fastDivideBy255(r * a + redChannel(*dest) * d);
+ g = fastDivideBy255(g * a + greenChannel(*dest) * d);
+ b = fastDivideBy255(b * a + blueChannel(*dest) * d);
+ a += fastDivideBy255(d * alphaChannel(*dest));
+
+ if (m_premultiplyAlpha)
+ *dest = makeRGBA(r, g, b, a);
+ else
+ *dest = makeUnPremultipliedRGBA(r, g, b, a);
+ }
+#endif
+
+ static bool isOverSize(const IntSize& size)
+ {
+ static unsigned long long MaxPixels = ((1 << 29) - 1);
+ unsigned long long pixels = static_cast<unsigned long long>(size.width()) * static_cast<unsigned long long>(size.height());
+ return pixels > MaxPixels;
+ }
+
+private:
+ ImageBackingStore(const IntSize& size, bool premultiplyAlpha = true)
+ : m_premultiplyAlpha(premultiplyAlpha)
+ {
+ ASSERT(!size.isEmpty() && !isOverSize(size));
+ setSize(size);
+ }
+
+ ImageBackingStore(const ImageBackingStore& other)
+ : m_size(other.m_size)
+ , m_premultiplyAlpha(other.m_premultiplyAlpha)
+ {
+ ASSERT(!m_size.isEmpty() && !isOverSize(m_size));
+ m_pixels = other.m_pixels->copy();
+ m_pixelsPtr = reinterpret_cast<RGBA32*>(const_cast<char*>(m_pixels->data()));
+ }
+
+ bool inBounds(const IntPoint& point) const
+ {
+ return IntRect(IntPoint(), m_size).contains(point);
+ }
+
+ bool inBounds(const IntRect& rect) const
+ {
+ return IntRect(IntPoint(), m_size).contains(rect);
+ }
+
+ RGBA32 pixelValue(unsigned r, unsigned g, unsigned b, unsigned a) const
+ {
+ if (m_premultiplyAlpha && !a)
+ return 0;
+
+ if (m_premultiplyAlpha && a < 255)
+ return makePremultipliedRGBA(r, g, b, a, false);
+
+ return makeRGBA(r, g, b, a);
+ }
+
+ RefPtr<SharedBuffer> m_pixels;
+ RGBA32* m_pixelsPtr { nullptr };
+ IntSize m_size;
+ IntRect m_frameRect; // This will always just be the entire buffer except for GIF and PNG frames
+ bool m_premultiplyAlpha { true };
+};
+
+}