diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/skia/skia/src/core/SkBlitter_A8.cpp | |
parent | Initial commit. (diff) | |
download | firefox-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.cpp | 313 |
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; +} + |