summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/core/SkBlitter_A8.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/skia/skia/src/core/SkBlitter_A8.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/skia/skia/src/core/SkBlitter_A8.cpp')
-rw-r--r--gfx/skia/skia/src/core/SkBlitter_A8.cpp313
1 files changed, 313 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/core/SkBlitter_A8.cpp b/gfx/skia/skia/src/core/SkBlitter_A8.cpp
new file mode 100644
index 0000000000..ea01296c99
--- /dev/null
+++ b/gfx/skia/skia/src/core/SkBlitter_A8.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkPaint.h"
+#include "include/core/SkTypes.h"
+#include "src/base/SkArenaAlloc.h"
+#include "src/core/SkBlitter_A8.h"
+
+SkA8_Coverage_Blitter::SkA8_Coverage_Blitter(const SkPixmap& device, const SkPaint& paint)
+ : fDevice(device)
+{
+ SkASSERT(nullptr == paint.getShader());
+ SkASSERT(nullptr == paint.getColorFilter());
+}
+
+void SkA8_Coverage_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
+ const int16_t runs[]) {
+ uint8_t* device = fDevice.writable_addr8(x, y);
+ SkDEBUGCODE(int totalCount = 0;)
+
+ for (;;) {
+ int count = runs[0];
+ SkASSERT(count >= 0);
+ if (count == 0) {
+ return;
+ }
+ if (antialias[0]) {
+ memset(device, antialias[0], count);
+ }
+ runs += count;
+ antialias += count;
+ device += count;
+
+ SkDEBUGCODE(totalCount += count;)
+ }
+ SkASSERT(fDevice.width() == totalCount);
+}
+
+void SkA8_Coverage_Blitter::blitH(int x, int y, int width) {
+ memset(fDevice.writable_addr8(x, y), 0xFF, width);
+}
+
+void SkA8_Coverage_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
+ if (0 == alpha) {
+ return;
+ }
+
+ uint8_t* dst = fDevice.writable_addr8(x, y);
+ const size_t dstRB = fDevice.rowBytes();
+ while (--height >= 0) {
+ *dst = alpha;
+ dst += dstRB;
+ }
+}
+
+void SkA8_Coverage_Blitter::blitRect(int x, int y, int width, int height) {
+ uint8_t* dst = fDevice.writable_addr8(x, y);
+ const size_t dstRB = fDevice.rowBytes();
+ while (--height >= 0) {
+ memset(dst, 0xFF, width);
+ dst += dstRB;
+ }
+}
+
+void SkA8_Coverage_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
+ if (SkMask::kA8_Format != mask.fFormat) {
+ this->SkBlitter::blitMask(mask, clip);
+ return;
+ }
+
+ int x = clip.fLeft;
+ int y = clip.fTop;
+ int width = clip.width();
+ int height = clip.height();
+
+ uint8_t* dst = fDevice.writable_addr8(x, y);
+ const uint8_t* src = mask.getAddr8(x, y);
+ const size_t srcRB = mask.fRowBytes;
+ const size_t dstRB = fDevice.rowBytes();
+
+ while (--height >= 0) {
+ memcpy(dst, src, width);
+ dst += dstRB;
+ src += srcRB;
+ }
+}
+
+const SkPixmap* SkA8_Coverage_Blitter::justAnOpaqueColor(uint32_t*) {
+ return nullptr;
+}
+
+//////////////
+
+static inline uint8_t div255(unsigned prod) {
+ SkASSERT(prod <= 255*255);
+ return (prod + 128) * 257 >> 16;
+}
+
+static inline unsigned u8_lerp(uint8_t a, uint8_t b, uint8_t t) {
+ return div255((255 - t) * a + t * b);
+}
+
+using AlphaProc = uint8_t(*)(uint8_t src, uint8_t dst);
+
+static uint8_t srcover_p (uint8_t src, uint8_t dst) { return src + div255((255 - src) * dst); }
+static uint8_t src_p (uint8_t src, uint8_t dst) { return src; }
+
+template <typename Mode> void A8_row_bw(uint8_t dst[], uint8_t src, int N, Mode proc) {
+ for (int i = 0; i < N; ++i) {
+ dst[i] = proc(src, dst[i]);
+ }
+}
+using A8_RowBlitBW = void(*)(uint8_t[], uint8_t, int);
+
+template <typename Mode>
+void A8_row_aa(uint8_t dst[], uint8_t src, int N, uint8_t aa, Mode proc, const bool canFoldAA) {
+ if (canFoldAA) {
+ src = div255(src * aa);
+ for (int i = 0; i < N; ++i) {
+ dst[i] = proc(src, dst[i]);
+ }
+ } else {
+ for (int i = 0; i < N; ++i) {
+ dst[i] = u8_lerp(dst[i], proc(src, dst[i]), aa);
+ }
+ }
+}
+using A8_RowBlitAA = void(*)(uint8_t[], uint8_t, int, uint8_t aa);
+
+#define WRAP_BLIT(proc, canFoldAA) \
+ proc, \
+ [](uint8_t dst[], uint8_t src, int N) \
+ { A8_row_bw(dst, src, N, proc); }, \
+ [](uint8_t dst[], uint8_t src, int N, uint8_t aa) \
+ { A8_row_aa(dst, src, N, aa, proc, canFoldAA); }
+
+struct A8_RowBlitBWPair {
+ SkBlendMode mode;
+ AlphaProc oneProc;
+ A8_RowBlitBW bwProc;
+ A8_RowBlitAA aaProc;
+};
+constexpr A8_RowBlitBWPair gA8_RowBlitPairs[] = {
+ {SkBlendMode::kSrcOver, WRAP_BLIT(srcover_p, true)},
+ {SkBlendMode::kSrc, WRAP_BLIT(src_p, false)},
+};
+#undef WRAP_BLIT
+
+static const A8_RowBlitBWPair* find_a8_rowproc_pair(SkBlendMode bm) {
+ for (auto& pair : gA8_RowBlitPairs) {
+ if (pair.mode == bm) {
+ return &pair;
+ }
+ }
+ return nullptr;
+}
+
+class SkA8_Blitter : public SkBlitter {
+public:
+ SkA8_Blitter(const SkPixmap& device, const SkPaint& paint);
+ void blitH(int x, int y, int width) override;
+ void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override;
+ void blitV(int x, int y, int height, SkAlpha alpha) override;
+ void blitRect(int x, int y, int width, int height) override;
+ void blitMask(const SkMask&, const SkIRect&) override;
+ const SkPixmap* justAnOpaqueColor(uint32_t*) override;
+
+private:
+ const SkPixmap fDevice;
+ AlphaProc fOneProc;
+ A8_RowBlitBW fBWProc;
+ A8_RowBlitAA fAAProc;
+ SkAlpha fSrc;
+
+ using INHERITED = SkBlitter;
+};
+
+SkA8_Blitter::SkA8_Blitter(const SkPixmap& device,
+ const SkPaint& paint) : fDevice(device) {
+ SkASSERT(nullptr == paint.getShader());
+ SkASSERT(nullptr == paint.getColorFilter());
+ auto mode = paint.asBlendMode();
+ SkASSERT(mode);
+ auto pair = find_a8_rowproc_pair(*mode);
+ SkASSERT(pair);
+
+ fOneProc = pair->oneProc;
+ fBWProc = pair->bwProc;
+ fAAProc = pair->aaProc;
+ fSrc = paint.getAlpha();
+}
+
+void SkA8_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
+ uint8_t* device = fDevice.writable_addr8(x, y);
+ SkDEBUGCODE(int totalCount = 0;)
+
+ for (;;) {
+ int count = runs[0];
+ SkASSERT(count >= 0);
+ if (count == 0) {
+ return;
+ }
+
+ if (antialias[0] == 0xFF) {
+ fBWProc(device, fSrc, count);
+ } else if (antialias[0] != 0) {
+ fAAProc(device, fSrc, count, antialias[0]);
+ }
+
+ runs += count;
+ antialias += count;
+ device += count;
+
+ SkDEBUGCODE(totalCount += count;)
+ }
+ SkASSERT(fDevice.width() == totalCount);
+}
+
+void SkA8_Blitter::blitH(int x, int y, int width) {
+ fBWProc(fDevice.writable_addr8(x, y), fSrc, width);
+}
+
+void SkA8_Blitter::blitV(int x, int y, int height, SkAlpha aa) {
+ uint8_t* device = fDevice.writable_addr8(x, y);
+ const size_t dstRB = fDevice.rowBytes();
+
+ if (aa == 0xFF) {
+ while (--height >= 0) {
+ *device = fOneProc(fSrc, *device);
+ device += dstRB;
+ }
+ } else if (aa != 0) {
+ while (--height >= 0) {
+ fAAProc(device, fSrc, 1, aa);
+ device += dstRB;
+ }
+ }
+}
+
+void SkA8_Blitter::blitRect(int x, int y, int width, int height) {
+ uint8_t* device = fDevice.writable_addr8(x, y);
+ const size_t dstRB = fDevice.rowBytes();
+
+ while (--height >= 0) {
+ fBWProc(device, fSrc, width);
+ device += dstRB;
+ }
+}
+
+void SkA8_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
+ if (SkMask::kA8_Format != mask.fFormat) {
+ this->INHERITED::blitMask(mask, clip);
+ return;
+ }
+
+ int x = clip.fLeft;
+ int y = clip.fTop;
+ int width = clip.width();
+ int height = clip.height();
+
+ uint8_t* dst = fDevice.writable_addr8(x, y);
+ const uint8_t* src = mask.getAddr8(x, y);
+ const size_t srcRB = mask.fRowBytes;
+ const size_t dstRB = fDevice.rowBytes();
+
+ while (--height >= 0) {
+ for (int i = 0; i < width; ++i) {
+ dst[i] = u8_lerp(dst[i], fOneProc(fSrc, dst[i]), src[i]);
+ }
+ dst += dstRB;
+ src += srcRB;
+ }
+}
+
+const SkPixmap* SkA8_Blitter::justAnOpaqueColor(uint32_t*) {
+ return nullptr;
+}
+
+//////////////////
+
+SkBlitter* SkA8Blitter_Choose(const SkPixmap& dst,
+ const SkMatrix& ctm,
+ const SkPaint& paint,
+ SkArenaAlloc* alloc,
+ bool drawCoverage,
+ sk_sp<SkShader> clipShader,
+ const SkSurfaceProps&) {
+ if (dst.colorType() != SkColorType::kAlpha_8_SkColorType) {
+ return nullptr;
+ }
+ if (paint.getShader() || paint.getColorFilter()) {
+ return nullptr;
+ }
+ if (clipShader) {
+ return nullptr; // would not be hard to support ...?
+ }
+
+ if (drawCoverage) {
+ return alloc->make<SkA8_Coverage_Blitter>(dst, paint);
+ } else {
+ // we only support certain blendmodes...
+ auto mode = paint.asBlendMode();
+ if (mode && find_a8_rowproc_pair(*mode)) {
+ return alloc->make<SkA8_Blitter>(dst, paint);
+ }
+ }
+ return nullptr;
+}
+