1/*
2 * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved.
3
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23template<typename PIXEL_T>
24static void inline cRasterPixels(PIXEL_T* dst, PIXEL_T val, uint32_t offset, int32_t len)
25{
26 dst += offset;
27
28 //fix the misaligned memory
29 auto alignOffset = (long long) dst % 8;
30 if (alignOffset > 0) {
31 if (sizeof(PIXEL_T) == 4) alignOffset /= 4;
32 else if (sizeof(PIXEL_T) == 1) alignOffset = 8 - alignOffset;
33 while (alignOffset > 0 && len > 0) {
34 *dst++ = val;
35 --len;
36 --alignOffset;
37 }
38 }
39
40 //64bits faster clear
41 if ((sizeof(PIXEL_T) == 4)) {
42 auto val64 = (uint64_t(val) << 32) | uint64_t(val);
43 while (len > 1) {
44 *reinterpret_cast<uint64_t*>(dst) = val64;
45 len -= 2;
46 dst += 2;
47 }
48 } else if (sizeof(PIXEL_T) == 1) {
49 auto val32 = (uint32_t(val) << 24) | (uint32_t(val) << 16) | (uint32_t(val) << 8) | uint32_t(val);
50 auto val64 = (uint64_t(val32) << 32) | val32;
51 while (len > 7) {
52 *reinterpret_cast<uint64_t*>(dst) = val64;
53 len -= 8;
54 dst += 8;
55 }
56 }
57
58 //leftovers
59 while (len--) *dst++ = val;
60}
61
62
63static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
64{
65 auto span = rle->spans;
66
67 //32bit channels
68 if (surface->channelSize == sizeof(uint32_t)) {
69 auto color = surface->join(r, g, b, a);
70 uint32_t src;
71 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
72 auto dst = &surface->buf32[span->y * surface->stride + span->x];
73 if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
74 else src = color;
75 auto ialpha = IA(src);
76 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
77 *dst = src + ALPHA_BLEND(*dst, ialpha);
78 }
79 }
80 //8bit grayscale
81 } else if (surface->channelSize == sizeof(uint8_t)) {
82 uint8_t src;
83 for (uint32_t i = 0; i < rle->size; ++i, ++span) {
84 auto dst = &surface->buf8[span->y * surface->stride + span->x];
85 if (span->coverage < 255) src = MULTIPLY(span->coverage, a);
86 else src = a;
87 auto ialpha = ~a;
88 for (uint32_t x = 0; x < span->len; ++x, ++dst) {
89 *dst = src + MULTIPLY(*dst, ialpha);
90 }
91 }
92 }
93 return true;
94}
95
96
97static bool inline cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
98{
99 auto h = static_cast<uint32_t>(region.max.y - region.min.y);
100 auto w = static_cast<uint32_t>(region.max.x - region.min.x);
101
102 //32bits channels
103 if (surface->channelSize == sizeof(uint32_t)) {
104 auto color = surface->join(r, g, b, 255);
105 auto buffer = surface->buf32 + (region.min.y * surface->stride) + region.min.x;
106 auto ialpha = 255 - a;
107 for (uint32_t y = 0; y < h; ++y) {
108 auto dst = &buffer[y * surface->stride];
109 for (uint32_t x = 0; x < w; ++x, ++dst) {
110 *dst = color + ALPHA_BLEND(*dst, ialpha);
111 }
112 }
113 //8bit grayscale
114 } else if (surface->channelSize == sizeof(uint8_t)) {
115 auto buffer = surface->buf8 + (region.min.y * surface->stride) + region.min.x;
116 auto ialpha = ~a;
117 for (uint32_t y = 0; y < h; ++y) {
118 auto dst = &buffer[y * surface->stride];
119 for (uint32_t x = 0; x < w; ++x, ++dst) {
120 *dst = a + MULTIPLY(*dst, ialpha);
121 }
122 }
123 }
124 return true;
125}
126
127
128static bool inline cRasterABGRtoARGB(Surface* surface)
129{
130 TVGLOG("SW_ENGINE", "Convert ColorSpace ABGR - ARGB [Size: %d x %d]", surface->w, surface->h);
131
132 //64bits faster converting
133 if (surface->w % 2 == 0) {
134 auto buffer = reinterpret_cast<uint64_t*>(surface->buf32);
135 for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride / 2) {
136 auto dst = buffer;
137 for (uint32_t x = 0; x < surface->w / 2; ++x, ++dst) {
138 auto c = *dst;
139 //flip Blue, Red channels
140 *dst = (c & 0xff000000ff000000) + ((c & 0x00ff000000ff0000) >> 16) + (c & 0x0000ff000000ff00) + ((c & 0x000000ff000000ff) << 16);
141 }
142 }
143 //default converting
144 } else {
145 auto buffer = surface->buf32;
146 for (uint32_t y = 0; y < surface->h; ++y, buffer += surface->stride) {
147 auto dst = buffer;
148 for (uint32_t x = 0; x < surface->w; ++x, ++dst) {
149 auto c = *dst;
150 //flip Blue, Red channels
151 *dst = (c & 0xff000000) + ((c & 0x00ff0000) >> 16) + (c & 0x0000ff00) + ((c & 0x000000ff) << 16);
152 }
153 }
154 }
155 return true;
156}
157
158
159static bool inline cRasterARGBtoABGR(Surface* surface)
160{
161 //exactly same with ABGRtoARGB
162 return cRasterABGRtoARGB(surface);
163}
164