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 | |
23 | template<typename PIXEL_T> |
24 | static 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 | |
63 | static 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 | |
97 | static 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 | |
128 | static 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 | |
159 | static bool inline cRasterARGBtoABGR(Surface* surface) |
160 | { |
161 | //exactly same with ABGRtoARGB |
162 | return cRasterABGRtoARGB(surface); |
163 | } |
164 | |