blob: 86c49d08aebf15564b431aa8fce14e1a32275219 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkBlitter.h"
9#include "SkAntiRun.h"
10#include "SkColor.h"
11#include "SkColorFilter.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
13#include "SkWriteBuffer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkMask.h"
15#include "SkMaskFilter.h"
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +000016#include "SkString.h"
reed@google.com45884902012-05-11 14:38:51 +000017#include "SkTLazy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000018#include "SkUtils.h"
halcanarya6814332015-05-27 08:53:36 -070019#include "SkXfermodeInterpretation.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020
reed395eabe2016-01-30 18:52:31 -080021// define this for testing srgb blits
reeda34be682016-02-15 07:48:35 -080022//#define SK_FORCE_PM4f_FOR_L32_BLITS
reed395eabe2016-01-30 18:52:31 -080023
reed@android.com845fdac2009-06-23 03:01:32 +000024SkBlitter::~SkBlitter() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000025
reed@google.comea033602012-12-14 13:13:55 +000026bool SkBlitter::isNullBlitter() const { return false; }
27
commit-bot@chromium.org80116dc2014-05-06 17:16:03 +000028bool SkBlitter::resetShaderContext(const SkShader::ContextRec&) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000029 return true;
30}
31
32SkShader::Context* SkBlitter::getShaderContext() const {
halcanary96fcdcc2015-08-27 07:41:13 -070033 return nullptr;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000034}
35
reed41e010c2015-06-09 12:16:53 -070036const SkPixmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
halcanary96fcdcc2015-08-27 07:41:13 -070037 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000038}
39
herb7df9e4a2016-06-10 13:01:27 -070040/*
reed@google.com82065d62011-02-07 15:30:46 +000041void SkBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000042 SkDEBUGFAIL("unimplemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000043}
44
herb7df9e4a2016-06-10 13:01:27 -070045
reed@google.com82065d62011-02-07 15:30:46 +000046void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
47 const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000048 SkDEBUGFAIL("unimplemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000049}
herb7df9e4a2016-06-10 13:01:27 -070050 */
reed@android.com8a1c16f2008-12-17 15:59:43 +000051
reed@google.com82065d62011-02-07 15:30:46 +000052void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
53 if (alpha == 255) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000054 this->blitRect(x, y, 1, height);
reed@google.com82065d62011-02-07 15:30:46 +000055 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 int16_t runs[2];
57 runs[0] = 1;
58 runs[1] = 0;
59
reed@google.com82065d62011-02-07 15:30:46 +000060 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 this->blitAntiH(x, y++, &alpha, runs);
reed@google.com82065d62011-02-07 15:30:46 +000062 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 }
64}
65
reed@google.com82065d62011-02-07 15:30:46 +000066void SkBlitter::blitRect(int x, int y, int width, int height) {
tomhudson@google.coma31ac732011-12-29 16:09:31 +000067 SkASSERT(width > 0);
reed@google.com82065d62011-02-07 15:30:46 +000068 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 this->blitH(x, y++, width);
reed@google.com82065d62011-02-07 15:30:46 +000070 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000071}
72
liyuqian38911a72016-10-04 11:23:22 -070073/// Default implementation doesn't check for easy optimizations
74/// such as alpha == 255; also uses blitV(), which some subclasses
tomhudson@google.com49eac192011-12-27 13:59:20 +000075/// may not support.
76void SkBlitter::blitAntiRect(int x, int y, int width, int height,
77 SkAlpha leftAlpha, SkAlpha rightAlpha) {
liyuqian38911a72016-10-04 11:23:22 -070078 if (leftAlpha > 0) { // we may send in x = -1 with leftAlpha = 0
79 this->blitV(x, y, height, leftAlpha);
80 }
81 x++;
tomhudson@google.coma31ac732011-12-29 16:09:31 +000082 if (width > 0) {
tomhudson@google.com47143592011-12-28 17:58:07 +000083 this->blitRect(x, y, width, height);
84 x += width;
85 }
liyuqian38911a72016-10-04 11:23:22 -070086 if (rightAlpha > 0) {
87 this->blitV(x, y, height, rightAlpha);
88 }
tomhudson@google.com49eac192011-12-27 13:59:20 +000089}
90
reed@android.com8a1c16f2008-12-17 15:59:43 +000091//////////////////////////////////////////////////////////////////////////////
92
reed@google.com82065d62011-02-07 15:30:46 +000093static inline void bits_to_runs(SkBlitter* blitter, int x, int y,
94 const uint8_t bits[],
herb5520ded2015-11-18 10:50:33 -080095 uint8_t left_mask, ptrdiff_t rowBytes,
96 uint8_t right_mask) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 int inFill = 0;
98 int pos = 0;
99
reed@google.com82065d62011-02-07 15:30:46 +0000100 while (--rowBytes >= 0) {
herb5520ded2015-11-18 10:50:33 -0800101 uint8_t b = *bits++ & left_mask;
reed@google.com82065d62011-02-07 15:30:46 +0000102 if (rowBytes == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 b &= right_mask;
reed@google.com82065d62011-02-07 15:30:46 +0000104 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105
herb5520ded2015-11-18 10:50:33 -0800106 for (uint8_t test = 0x80U; test != 0; test >>= 1) {
reed@google.com82065d62011-02-07 15:30:46 +0000107 if (b & test) {
108 if (!inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 pos = x;
110 inFill = true;
111 }
reed@google.com82065d62011-02-07 15:30:46 +0000112 } else {
113 if (inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 blitter->blitH(pos, y, x - pos);
115 inFill = false;
116 }
117 }
118 x += 1;
119 }
herb5520ded2015-11-18 10:50:33 -0800120 left_mask = 0xFFU;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 }
122
123 // final cleanup
reed@google.com82065d62011-02-07 15:30:46 +0000124 if (inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125 blitter->blitH(pos, y, x - pos);
reed@google.com82065d62011-02-07 15:30:46 +0000126 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127}
128
herb5520ded2015-11-18 10:50:33 -0800129// maskBitCount is the number of 1's to place in the mask. It must be in the range between 1 and 8.
130static uint8_t generate_right_mask(int maskBitCount) {
131 return static_cast<uint8_t>(0xFF00U >> maskBitCount);
132}
133
reed@google.com82065d62011-02-07 15:30:46 +0000134void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 SkASSERT(mask.fBounds.contains(clip));
136
reedd96e7e52016-02-17 07:15:29 -0800137 if (mask.fFormat == SkMask::kLCD16_Format) {
138 return; // needs to be handled by subclass
139 }
140
reed@google.com82065d62011-02-07 15:30:46 +0000141 if (mask.fFormat == SkMask::kBW_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 int cx = clip.fLeft;
143 int cy = clip.fTop;
144 int maskLeft = mask.fBounds.fLeft;
herb5520ded2015-11-18 10:50:33 -0800145 int maskRowBytes = mask.fRowBytes;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 int height = clip.height();
147
148 const uint8_t* bits = mask.getAddr1(cx, cy);
149
herb5520ded2015-11-18 10:50:33 -0800150 SkDEBUGCODE(const uint8_t* endOfImage =
151 mask.fImage + (mask.fBounds.height() - 1) * maskRowBytes
152 + ((mask.fBounds.width() + 7) >> 3));
153
reed@google.com82065d62011-02-07 15:30:46 +0000154 if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) {
155 while (--height >= 0) {
herb5520ded2015-11-18 10:50:33 -0800156 int affectedRightBit = mask.fBounds.width() - 1;
157 ptrdiff_t rowBytes = (affectedRightBit >> 3) + 1;
158 SkASSERT(bits + rowBytes <= endOfImage);
159 U8CPU rightMask = generate_right_mask((affectedRightBit & 7) + 1);
160 bits_to_runs(this, cx, cy, bits, 0xFF, rowBytes, rightMask);
161 bits += maskRowBytes;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 cy += 1;
163 }
reed@google.com82065d62011-02-07 15:30:46 +0000164 } else {
herb3be72b02016-06-24 13:02:31 -0700165 // Bits is calculated as the offset into the mask at the point {cx, cy} therefore, all
herb5520ded2015-11-18 10:50:33 -0800166 // addressing into the bit mask is relative to that point. Since this is an address
167 // calculated from a arbitrary bit in that byte, calculate the left most bit.
168 int bitsLeft = cx - ((cx - maskLeft) & 7);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
herb5520ded2015-11-18 10:50:33 -0800170 // Everything is relative to the bitsLeft.
171 int leftEdge = cx - bitsLeft;
172 SkASSERT(leftEdge >= 0);
173 int rightEdge = clip.fRight - bitsLeft;
174 SkASSERT(rightEdge > leftEdge);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
herb5520ded2015-11-18 10:50:33 -0800176 // Calculate left byte and mask
177 const uint8_t* leftByte = bits;
178 U8CPU leftMask = 0xFFU >> (leftEdge & 7);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179
herb5520ded2015-11-18 10:50:33 -0800180 // Calculate right byte and mask
181 int affectedRightBit = rightEdge - 1;
182 const uint8_t* rightByte = bits + (affectedRightBit >> 3);
183 U8CPU rightMask = generate_right_mask((affectedRightBit & 7) + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184
herb5520ded2015-11-18 10:50:33 -0800185 // leftByte and rightByte are byte locations therefore, to get a count of bytes the
186 // code must add one.
187 ptrdiff_t rowBytes = rightByte - leftByte + 1;
188
189 while (--height >= 0) {
190 SkASSERT(bits + rowBytes <= endOfImage);
191 bits_to_runs(this, bitsLeft, cy, bits, leftMask, rowBytes, rightMask);
192 bits += maskRowBytes;
193 cy += 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 }
195 }
reed@google.com82065d62011-02-07 15:30:46 +0000196 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 int width = clip.width();
198 SkAutoSTMalloc<64, int16_t> runStorage(width + 1);
199 int16_t* runs = runStorage.get();
reed@google.com79891862011-10-18 15:44:57 +0000200 const uint8_t* aa = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201
202 sk_memset16((uint16_t*)runs, 1, width);
203 runs[width] = 0;
204
205 int height = clip.height();
206 int y = clip.fTop;
reed@google.com82065d62011-02-07 15:30:46 +0000207 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 this->blitAntiH(clip.fLeft, y, aa, runs);
209 aa += mask.fRowBytes;
210 y += 1;
211 }
212 }
213}
214
215/////////////////////// these guys are not virtual, just a helpers
216
217void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) {
218 if (clip.quickReject(mask.fBounds)) {
219 return;
220 }
reed@google.com82065d62011-02-07 15:30:46 +0000221
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 SkRegion::Cliperator clipper(clip, mask.fBounds);
reed@google.com82065d62011-02-07 15:30:46 +0000223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 while (!clipper.done()) {
225 const SkIRect& cr = clipper.rect();
226 this->blitMask(mask, cr);
227 clipper.next();
228 }
229}
230
231void SkBlitter::blitRectRegion(const SkIRect& rect, const SkRegion& clip) {
232 SkRegion::Cliperator clipper(clip, rect);
reed@google.com82065d62011-02-07 15:30:46 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 while (!clipper.done()) {
235 const SkIRect& cr = clipper.rect();
236 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
237 clipper.next();
238 }
239}
240
241void SkBlitter::blitRegion(const SkRegion& clip) {
242 SkRegion::Iterator iter(clip);
reed@google.com82065d62011-02-07 15:30:46 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 while (!iter.done()) {
245 const SkIRect& cr = iter.rect();
246 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
247 iter.next();
248 }
249}
250
reed@google.com82065d62011-02-07 15:30:46 +0000251///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252
reed@google.com82065d62011-02-07 15:30:46 +0000253void SkNullBlitter::blitH(int x, int y, int width) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254
reed@google.com82065d62011-02-07 15:30:46 +0000255void SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
256 const int16_t runs[]) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257
reed@google.com82065d62011-02-07 15:30:46 +0000258void SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259
reed@google.com82065d62011-02-07 15:30:46 +0000260void SkNullBlitter::blitRect(int x, int y, int width, int height) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261
reed@google.com82065d62011-02-07 15:30:46 +0000262void SkNullBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263
reed41e010c2015-06-09 12:16:53 -0700264const SkPixmap* SkNullBlitter::justAnOpaqueColor(uint32_t* value) {
halcanary96fcdcc2015-08-27 07:41:13 -0700265 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266}
267
reed@google.comea033602012-12-14 13:13:55 +0000268bool SkNullBlitter::isNullBlitter() const { return true; }
269
reed@google.com82065d62011-02-07 15:30:46 +0000270///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271
reed@google.com82065d62011-02-07 15:30:46 +0000272static int compute_anti_width(const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273 int width = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000274
275 for (;;) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 int count = runs[0];
reed@google.com82065d62011-02-07 15:30:46 +0000277
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 SkASSERT(count >= 0);
reed@google.com82065d62011-02-07 15:30:46 +0000279 if (count == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 break;
reed@google.com82065d62011-02-07 15:30:46 +0000281 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 width += count;
283 runs += count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 }
285 return width;
286}
287
reed@google.com82065d62011-02-07 15:30:46 +0000288static inline bool y_in_rect(int y, const SkIRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
290}
291
reed@google.com82065d62011-02-07 15:30:46 +0000292static inline bool x_in_rect(int x, const SkIRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
294}
295
reed@google.com82065d62011-02-07 15:30:46 +0000296void SkRectClipBlitter::blitH(int left, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297 SkASSERT(width > 0);
298
reed@google.com82065d62011-02-07 15:30:46 +0000299 if (!y_in_rect(y, fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000300 return;
reed@google.com82065d62011-02-07 15:30:46 +0000301 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302
303 int right = left + width;
304
reed@google.com82065d62011-02-07 15:30:46 +0000305 if (left < fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000306 left = fClipRect.fLeft;
reed@google.com82065d62011-02-07 15:30:46 +0000307 }
308 if (right > fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309 right = fClipRect.fRight;
reed@google.com82065d62011-02-07 15:30:46 +0000310 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311
312 width = right - left;
reed@google.com82065d62011-02-07 15:30:46 +0000313 if (width > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 fBlitter->blitH(left, y, width);
reed@google.com82065d62011-02-07 15:30:46 +0000315 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316}
317
reed@google.com82065d62011-02-07 15:30:46 +0000318void SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha aa[],
319 const int16_t runs[]) {
320 if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321 return;
reed@google.com82065d62011-02-07 15:30:46 +0000322 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323
324 int x0 = left;
325 int x1 = left + compute_anti_width(runs);
326
reed@google.com82065d62011-02-07 15:30:46 +0000327 if (x1 <= fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 return;
reed@google.com82065d62011-02-07 15:30:46 +0000329 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330
331 SkASSERT(x0 < x1);
reed@google.com82065d62011-02-07 15:30:46 +0000332 if (x0 < fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 int dx = fClipRect.fLeft - x0;
334 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, dx);
335 runs += dx;
336 aa += dx;
337 x0 = fClipRect.fLeft;
338 }
339
340 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
reed@google.com82065d62011-02-07 15:30:46 +0000341 if (x1 > fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 x1 = fClipRect.fRight;
343 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, x1 - x0);
344 ((int16_t*)runs)[x1 - x0] = 0;
345 }
346
347 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
348 SkASSERT(compute_anti_width(runs) == x1 - x0);
349
350 fBlitter->blitAntiH(x0, y, aa, runs);
351}
352
reed@google.com82065d62011-02-07 15:30:46 +0000353void SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 SkASSERT(height > 0);
355
reed@google.com82065d62011-02-07 15:30:46 +0000356 if (!x_in_rect(x, fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 return;
reed@google.com82065d62011-02-07 15:30:46 +0000358 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359
360 int y0 = y;
361 int y1 = y + height;
362
reed@google.com82065d62011-02-07 15:30:46 +0000363 if (y0 < fClipRect.fTop) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000364 y0 = fClipRect.fTop;
reed@google.com82065d62011-02-07 15:30:46 +0000365 }
366 if (y1 > fClipRect.fBottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 y1 = fClipRect.fBottom;
reed@google.com82065d62011-02-07 15:30:46 +0000368 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369
reed@google.com82065d62011-02-07 15:30:46 +0000370 if (y0 < y1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371 fBlitter->blitV(x, y0, y1 - y0, alpha);
reed@google.com82065d62011-02-07 15:30:46 +0000372 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373}
374
reed@google.com82065d62011-02-07 15:30:46 +0000375void SkRectClipBlitter::blitRect(int left, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376 SkIRect r;
377
378 r.set(left, y, left + width, y + height);
reed@google.com82065d62011-02-07 15:30:46 +0000379 if (r.intersect(fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
reed@google.com82065d62011-02-07 15:30:46 +0000381 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382}
383
tomhudson@google.com49eac192011-12-27 13:59:20 +0000384void SkRectClipBlitter::blitAntiRect(int left, int y, int width, int height,
385 SkAlpha leftAlpha, SkAlpha rightAlpha) {
386 SkIRect r;
387
388 // The *true* width of the rectangle blitted is width+2:
389 r.set(left, y, left + width + 2, y + height);
390 if (r.intersect(fClipRect)) {
391 if (r.fLeft != left) {
392 SkASSERT(r.fLeft > left);
393 leftAlpha = 255;
394 }
395 if (r.fRight != left + width + 2) {
396 SkASSERT(r.fRight < left + width + 2);
397 rightAlpha = 255;
398 }
399 if (255 == leftAlpha && 255 == rightAlpha) {
400 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
401 } else if (1 == r.width()) {
402 if (r.fLeft == left) {
403 fBlitter->blitV(r.fLeft, r.fTop, r.height(), leftAlpha);
404 } else {
405 SkASSERT(r.fLeft == left + width + 1);
406 fBlitter->blitV(r.fLeft, r.fTop, r.height(), rightAlpha);
407 }
408 } else {
409 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
410 leftAlpha, rightAlpha);
411 }
412 }
413}
414
reed@google.com82065d62011-02-07 15:30:46 +0000415void SkRectClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416 SkASSERT(mask.fBounds.contains(clip));
417
418 SkIRect r = clip;
419
reed@google.com82065d62011-02-07 15:30:46 +0000420 if (r.intersect(fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000421 fBlitter->blitMask(mask, r);
reed@google.com82065d62011-02-07 15:30:46 +0000422 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423}
424
reed41e010c2015-06-09 12:16:53 -0700425const SkPixmap* SkRectClipBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 return fBlitter->justAnOpaqueColor(value);
427}
428
reed@google.com82065d62011-02-07 15:30:46 +0000429///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000430
reed@google.com82065d62011-02-07 15:30:46 +0000431void SkRgnClipBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 SkRegion::Spanerator span(*fRgn, y, x, x + width);
433 int left, right;
434
reed@google.com82065d62011-02-07 15:30:46 +0000435 while (span.next(&left, &right)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000436 SkASSERT(left < right);
437 fBlitter->blitH(left, y, right - left);
438 }
439}
440
reed@google.com82065d62011-02-07 15:30:46 +0000441void SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
442 const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 int width = compute_anti_width(runs);
444 SkRegion::Spanerator span(*fRgn, y, x, x + width);
445 int left, right;
446 SkDEBUGCODE(const SkIRect& bounds = fRgn->getBounds();)
reed@google.com82065d62011-02-07 15:30:46 +0000447
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448 int prevRite = x;
reed@google.com82065d62011-02-07 15:30:46 +0000449 while (span.next(&left, &right)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450 SkASSERT(x <= left);
451 SkASSERT(left < right);
452 SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
reed@google.com82065d62011-02-07 15:30:46 +0000453
reed@android.com8a1c16f2008-12-17 15:59:43 +0000454 SkAlphaRuns::Break((int16_t*)runs, (uint8_t*)aa, left - x, right - left);
455
456 // now zero before left
reed@google.com82065d62011-02-07 15:30:46 +0000457 if (left > prevRite) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458 int index = prevRite - x;
459 ((uint8_t*)aa)[index] = 0; // skip runs after right
460 ((int16_t*)runs)[index] = SkToS16(left - prevRite);
461 }
reed@google.com82065d62011-02-07 15:30:46 +0000462
reed@android.com8a1c16f2008-12-17 15:59:43 +0000463 prevRite = right;
464 }
reed@google.com82065d62011-02-07 15:30:46 +0000465
466 if (prevRite > x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467 ((int16_t*)runs)[prevRite - x] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000468
reed@android.com8a1c16f2008-12-17 15:59:43 +0000469 if (x < 0) {
470 int skip = runs[0];
471 SkASSERT(skip >= -x);
472 aa += skip;
473 runs += skip;
474 x += skip;
475 }
476 fBlitter->blitAntiH(x, y, aa, runs);
477 }
478}
479
reed@google.com82065d62011-02-07 15:30:46 +0000480void SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481 SkIRect bounds;
482 bounds.set(x, y, x + 1, y + height);
483
484 SkRegion::Cliperator iter(*fRgn, bounds);
485
reed@google.com82065d62011-02-07 15:30:46 +0000486 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000487 const SkIRect& r = iter.rect();
488 SkASSERT(bounds.contains(r));
489
490 fBlitter->blitV(x, r.fTop, r.height(), alpha);
491 iter.next();
492 }
493}
494
reed@google.com82065d62011-02-07 15:30:46 +0000495void SkRgnClipBlitter::blitRect(int x, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496 SkIRect bounds;
497 bounds.set(x, y, x + width, y + height);
498
499 SkRegion::Cliperator iter(*fRgn, bounds);
500
reed@google.com82065d62011-02-07 15:30:46 +0000501 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502 const SkIRect& r = iter.rect();
503 SkASSERT(bounds.contains(r));
504
505 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
506 iter.next();
507 }
508}
509
tomhudson@google.com49eac192011-12-27 13:59:20 +0000510void SkRgnClipBlitter::blitAntiRect(int x, int y, int width, int height,
511 SkAlpha leftAlpha, SkAlpha rightAlpha) {
512 // The *true* width of the rectangle to blit is width + 2
513 SkIRect bounds;
514 bounds.set(x, y, x + width + 2, y + height);
515
516 SkRegion::Cliperator iter(*fRgn, bounds);
517
518 while (!iter.done()) {
519 const SkIRect& r = iter.rect();
520 SkASSERT(bounds.contains(r));
521 SkASSERT(r.fLeft >= x);
tomhudson@google.com31bab392012-01-03 20:12:42 +0000522 SkASSERT(r.fRight <= x + width + 2);
tomhudson@google.com49eac192011-12-27 13:59:20 +0000523
524 SkAlpha effectiveLeftAlpha = (r.fLeft == x) ? leftAlpha : 255;
525 SkAlpha effectiveRightAlpha = (r.fRight == x + width + 2) ?
526 rightAlpha : 255;
527
528 if (255 == effectiveLeftAlpha && 255 == effectiveRightAlpha) {
529 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
530 } else if (1 == r.width()) {
531 if (r.fLeft == x) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000532 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
tomhudson@google.com49eac192011-12-27 13:59:20 +0000533 effectiveLeftAlpha);
534 } else {
535 SkASSERT(r.fLeft == x + width + 1);
536 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
537 effectiveRightAlpha);
538 }
539 } else {
540 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
541 effectiveLeftAlpha, effectiveRightAlpha);
542 }
543 iter.next();
544 }
545}
546
547
reed@google.com82065d62011-02-07 15:30:46 +0000548void SkRgnClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549 SkASSERT(mask.fBounds.contains(clip));
550
551 SkRegion::Cliperator iter(*fRgn, clip);
552 const SkIRect& r = iter.rect();
553 SkBlitter* blitter = fBlitter;
554
reed@google.com82065d62011-02-07 15:30:46 +0000555 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556 blitter->blitMask(mask, r);
557 iter.next();
558 }
559}
560
reed41e010c2015-06-09 12:16:53 -0700561const SkPixmap* SkRgnClipBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 return fBlitter->justAnOpaqueColor(value);
563}
564
reed@google.com82065d62011-02-07 15:30:46 +0000565///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566
reed@google.com82065d62011-02-07 15:30:46 +0000567SkBlitter* SkBlitterClipper::apply(SkBlitter* blitter, const SkRegion* clip,
568 const SkIRect* ir) {
569 if (clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570 const SkIRect& clipR = clip->getBounds();
571
reed@google.com82065d62011-02-07 15:30:46 +0000572 if (clip->isEmpty() || (ir && !SkIRect::Intersects(clipR, *ir))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573 blitter = &fNullBlitter;
reed@google.com82065d62011-02-07 15:30:46 +0000574 } else if (clip->isRect()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700575 if (ir == nullptr || !clipR.contains(*ir)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576 fRectBlitter.init(blitter, clipR);
577 blitter = &fRectBlitter;
578 }
reed@google.com82065d62011-02-07 15:30:46 +0000579 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580 fRgnBlitter.init(blitter, clip);
581 blitter = &fRgnBlitter;
582 }
583 }
584 return blitter;
585}
586
reed@google.com82065d62011-02-07 15:30:46 +0000587///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588
589#include "SkColorShader.h"
590#include "SkColorPriv.h"
591
592class Sk3DShader : public SkShader {
593public:
reed8a21c9f2016-03-08 18:50:00 -0800594 Sk3DShader(sk_sp<SkShader> proxy) : fProxy(std::move(proxy)) {}
reed@google.com82065d62011-02-07 15:30:46 +0000595
reed773ceda2016-03-03 18:18:25 -0800596 size_t onContextSize(const ContextRec& rec) const override {
reeda0cee5f2016-03-04 07:38:11 -0800597 size_t size = sizeof(Sk3DShaderContext);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000598 if (fProxy) {
fmalita8d9f2e42016-02-22 10:39:41 -0800599 size += fProxy->contextSize(rec);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000600 }
601 return size;
602 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603
mtklein36352bf2015-03-25 18:17:31 -0700604 Context* onCreateContext(const ContextRec& rec, void* storage) const override {
halcanary96fcdcc2015-08-27 07:41:13 -0700605 SkShader::Context* proxyContext = nullptr;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000606 if (fProxy) {
607 char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext);
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000608 proxyContext = fProxy->createContext(rec, proxyContextStorage);
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000609 if (!proxyContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700610 return nullptr;
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000611 }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000612 }
halcanary385fe4d2015-08-26 13:07:48 -0700613 return new (storage) Sk3DShaderContext(*this, rec, proxyContext);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000616 class Sk3DShaderContext : public SkShader::Context {
617 public:
618 // Calls proxyContext's destructor but will NOT free its memory.
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000619 Sk3DShaderContext(const Sk3DShader& shader, const ContextRec& rec,
620 SkShader::Context* proxyContext)
621 : INHERITED(shader, rec)
halcanary96fcdcc2015-08-27 07:41:13 -0700622 , fMask(nullptr)
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000623 , fProxyContext(proxyContext)
624 {
625 if (!fProxyContext) {
commit-bot@chromium.orge901b6d2014-05-01 19:31:31 +0000626 fPMColor = SkPreMultiplyColor(rec.fPaint->getColor());
commit-bot@chromium.orgbc2f1dc2014-04-23 09:11:58 +0000627 }
628 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000630 virtual ~Sk3DShaderContext() {
631 if (fProxyContext) {
632 fProxyContext->~Context();
633 }
634 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635
mtklein36352bf2015-03-25 18:17:31 -0700636 void set3DMask(const SkMask* mask) override { fMask = mask; }
commit-bot@chromium.org001f4ed2014-04-16 10:16:39 +0000637
mtklein36352bf2015-03-25 18:17:31 -0700638 void shadeSpan(int x, int y, SkPMColor span[], int count) override {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000639 if (fProxyContext) {
640 fProxyContext->shadeSpan(x, y, span, count);
641 }
commit-bot@chromium.orgbc2f1dc2014-04-23 09:11:58 +0000642
halcanary96fcdcc2015-08-27 07:41:13 -0700643 if (fMask == nullptr) {
644 if (fProxyContext == nullptr) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000645 sk_memset32(span, fPMColor, count);
646 }
647 return;
648 }
649
650 SkASSERT(fMask->fBounds.contains(x, y));
651 SkASSERT(fMask->fBounds.contains(x + count - 1, y));
652
653 size_t size = fMask->computeImageSize();
654 const uint8_t* alpha = fMask->getAddr8(x, y);
655 const uint8_t* mulp = alpha + size;
656 const uint8_t* addp = mulp + size;
657
658 if (fProxyContext) {
659 for (int i = 0; i < count; i++) {
660 if (alpha[i]) {
661 SkPMColor c = span[i];
662 if (c) {
663 unsigned a = SkGetPackedA32(c);
664 unsigned r = SkGetPackedR32(c);
665 unsigned g = SkGetPackedG32(c);
666 unsigned b = SkGetPackedB32(c);
667
668 unsigned mul = SkAlpha255To256(mulp[i]);
669 unsigned add = addp[i];
670
671 r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
672 g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
673 b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
674
675 span[i] = SkPackARGB32(a, r, g, b);
676 }
677 } else {
678 span[i] = 0;
679 }
680 }
681 } else { // color
682 unsigned a = SkGetPackedA32(fPMColor);
683 unsigned r = SkGetPackedR32(fPMColor);
684 unsigned g = SkGetPackedG32(fPMColor);
685 unsigned b = SkGetPackedB32(fPMColor);
686 for (int i = 0; i < count; i++) {
687 if (alpha[i]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 unsigned mul = SkAlpha255To256(mulp[i]);
689 unsigned add = addp[i];
690
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000691 span[i] = SkPackARGB32( a,
692 SkFastMin32(SkAlphaMul(r, mul) + add, a),
693 SkFastMin32(SkAlphaMul(g, mul) + add, a),
694 SkFastMin32(SkAlphaMul(b, mul) + add, a));
695 } else {
696 span[i] = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 }
reed@google.com82065d62011-02-07 15:30:46 +0000698 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 }
700 }
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000701
702 private:
703 // Unowned.
704 const SkMask* fMask;
705 // Memory is unowned, but we need to call the destructor.
706 SkShader::Context* fProxyContext;
707 SkPMColor fPMColor;
708
709 typedef SkShader::Context INHERITED;
710 };
reed@google.com82065d62011-02-07 15:30:46 +0000711
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000712#ifndef SK_IGNORE_TO_STRING
mtklein36352bf2015-03-25 18:17:31 -0700713 void toString(SkString* str) const override {
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000714 str->append("Sk3DShader: (");
715
bsalomon49f085d2014-09-05 13:34:00 -0700716 if (fProxy) {
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000717 str->append("Proxy: ");
718 fProxy->toString(str);
719 }
720
721 this->INHERITED::toString(str);
722
723 str->append(")");
724 }
725#endif
726
djsollen@google.comba28d032012-03-26 17:57:35 +0000727 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Sk3DShader)
728
reed@android.com8a1c16f2008-12-17 15:59:43 +0000729protected:
mtklein36352bf2015-03-25 18:17:31 -0700730 void flatten(SkWriteBuffer& buffer) const override {
reed8a21c9f2016-03-08 18:50:00 -0800731 buffer.writeFlattenable(fProxy.get());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 }
reed@google.com82065d62011-02-07 15:30:46 +0000733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734private:
reed8a21c9f2016-03-08 18:50:00 -0800735 sk_sp<SkShader> fProxy;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736
737 typedef SkShader INHERITED;
738};
739
reed60c9b582016-04-03 09:11:13 -0700740sk_sp<SkFlattenable> Sk3DShader::CreateProc(SkReadBuffer& buffer) {
741 return sk_make_sp<Sk3DShader>(buffer.readShader());
reed9fa60da2014-08-21 07:59:51 -0700742}
743
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744class Sk3DBlitter : public SkBlitter {
745public:
reedcc0e3112014-09-10 10:20:24 -0700746 Sk3DBlitter(SkBlitter* proxy, SkShader::Context* shaderContext)
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000747 : fProxy(proxy)
reedcc0e3112014-09-10 10:20:24 -0700748 , fShaderContext(shaderContext)
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000749 {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750
mtklein36352bf2015-03-25 18:17:31 -0700751 void blitH(int x, int y, int width) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752 fProxy->blitH(x, y, width);
753 }
reed@google.com82065d62011-02-07 15:30:46 +0000754
reed60c9b582016-04-03 09:11:13 -0700755 void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000756 fProxy->blitAntiH(x, y, antialias, runs);
757 }
reed@google.com82065d62011-02-07 15:30:46 +0000758
mtklein36352bf2015-03-25 18:17:31 -0700759 void blitV(int x, int y, int height, SkAlpha alpha) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 fProxy->blitV(x, y, height, alpha);
761 }
reed@google.com82065d62011-02-07 15:30:46 +0000762
mtklein36352bf2015-03-25 18:17:31 -0700763 void blitRect(int x, int y, int width, int height) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000764 fProxy->blitRect(x, y, width, height);
765 }
reed@google.com82065d62011-02-07 15:30:46 +0000766
mtklein36352bf2015-03-25 18:17:31 -0700767 void blitMask(const SkMask& mask, const SkIRect& clip) override {
reed@google.com82065d62011-02-07 15:30:46 +0000768 if (mask.fFormat == SkMask::k3D_Format) {
reedcc0e3112014-09-10 10:20:24 -0700769 fShaderContext->set3DMask(&mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770
771 ((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
772 fProxy->blitMask(mask, clip);
773 ((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
774
halcanary96fcdcc2015-08-27 07:41:13 -0700775 fShaderContext->set3DMask(nullptr);
reed@google.com82065d62011-02-07 15:30:46 +0000776 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 fProxy->blitMask(mask, clip);
reed@google.com82065d62011-02-07 15:30:46 +0000778 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779 }
reed@google.com82065d62011-02-07 15:30:46 +0000780
reed@android.com8a1c16f2008-12-17 15:59:43 +0000781private:
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000782 // Both pointers are unowned. They will be deleted by SkSmallAllocator.
reedcc0e3112014-09-10 10:20:24 -0700783 SkBlitter* fProxy;
784 SkShader::Context* fShaderContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000785};
786
reed@google.com82065d62011-02-07 15:30:46 +0000787///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000788
789#include "SkCoreBlitters.h"
790
fmalitad0c4e092016-02-22 17:19:04 -0800791SkShader::ContextRec::DstType SkBlitter::PreferredShaderDest(const SkImageInfo& dstInfo) {
792#ifdef SK_FORCE_PM4f_FOR_L32_BLITS
793 return SkShader::ContextRec::kPM4f_DstType;
794#else
reed960b2d62016-06-17 09:26:41 -0700795 return (dstInfo.gammaCloseToSRGB() || dstInfo.colorType() == kRGBA_F16_SkColorType)
fmalitad0c4e092016-02-22 17:19:04 -0800796 ? SkShader::ContextRec::kPM4f_DstType
797 : SkShader::ContextRec::kPMColor_DstType;
798#endif
799}
800
reed41e010c2015-06-09 12:16:53 -0700801SkBlitter* SkBlitter::Choose(const SkPixmap& device,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000802 const SkMatrix& matrix,
reed@google.com6b7aee32011-04-19 18:36:09 +0000803 const SkPaint& origPaint,
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000804 SkTBlitterAllocator* allocator,
reed@google.com126f7f52013-11-07 16:06:53 +0000805 bool drawCoverage) {
halcanary96fcdcc2015-08-27 07:41:13 -0700806 SkASSERT(allocator != nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000807
reed@android.com8a1c16f2008-12-17 15:59:43 +0000808 // which check, in case we're being called by a client with a dummy device
809 // (e.g. they have a bounder that always aborts the draw)
reed@google.com900ecf22014-02-20 20:55:37 +0000810 if (kUnknown_SkColorType == device.colorType() ||
811 (drawCoverage && (kAlpha_8_SkColorType != device.colorType()))) {
bsalomonb0ae6492014-12-29 07:05:27 -0800812 return allocator->createT<SkNullBlitter>();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000813 }
814
reed@google.com45884902012-05-11 14:38:51 +0000815 SkShader* shader = origPaint.getShader();
816 SkColorFilter* cf = origPaint.getColorFilter();
reed374772b2016-10-05 17:33:02 -0700817 SkBlendMode mode = origPaint.getBlendMode();
reedfe630452016-03-25 09:08:00 -0700818 sk_sp<Sk3DShader> shader3D;
reed@google.com45884902012-05-11 14:38:51 +0000819
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000820 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000821
halcanary96fcdcc2015-08-27 07:41:13 -0700822 if (origPaint.getMaskFilter() != nullptr &&
reed@google.com45884902012-05-11 14:38:51 +0000823 origPaint.getMaskFilter()->getFormat() == SkMask::k3D_Format) {
reedfe630452016-03-25 09:08:00 -0700824 shader3D = sk_make_sp<Sk3DShader>(sk_ref_sp(shader));
reed@google.com45884902012-05-11 14:38:51 +0000825 // we know we haven't initialized lazyPaint yet, so just do it
reedfe630452016-03-25 09:08:00 -0700826 paint.writable()->setShader(shader3D);
827 shader = shader3D.get();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000828 }
829
reed374772b2016-10-05 17:33:02 -0700830 if (mode != SkBlendMode::kSrcOver) {
halcanarya6814332015-05-27 08:53:36 -0700831 bool deviceIsOpaque = kRGB_565_SkColorType == device.colorType();
832 switch (SkInterpretXfermode(*paint, deviceIsOpaque)) {
833 case kSrcOver_SkXfermodeInterpretation:
reed374772b2016-10-05 17:33:02 -0700834 mode = SkBlendMode::kSrcOver;
835 paint.writable()->setBlendMode(mode);
reed@android.comd252db02009-04-01 18:31:44 +0000836 break;
halcanarya6814332015-05-27 08:53:36 -0700837 case kSkipDrawing_SkXfermodeInterpretation:{
bsalomonb0ae6492014-12-29 07:05:27 -0800838 return allocator->createT<SkNullBlitter>();
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000839 }
reed@android.comd252db02009-04-01 18:31:44 +0000840 default:
841 break;
842 }
843 }
844
reed@google.com13201e72012-11-16 13:20:41 +0000845 /*
846 * If the xfermode is CLEAR, then we can completely ignore the installed
847 * color/shader/colorfilter, and just pretend we're SRC + color==0. This
848 * will fall into our optimizations for SRC mode.
849 */
reed374772b2016-10-05 17:33:02 -0700850 if (mode == SkBlendMode::kClear) {
reed@google.com13201e72012-11-16 13:20:41 +0000851 SkPaint* p = paint.writable();
reedfe630452016-03-25 09:08:00 -0700852 p->setShader(nullptr);
853 shader = nullptr;
reedd053ce92016-03-22 10:17:23 -0700854 p->setColorFilter(nullptr);
855 cf = nullptr;
reed374772b2016-10-05 17:33:02 -0700856 p->setBlendMode(mode = SkBlendMode::kSrc);
reed@google.com13201e72012-11-16 13:20:41 +0000857 p->setColor(0);
858 }
reed@google.com13201e72012-11-16 13:20:41 +0000859
Mike Kleine71b1672017-01-13 07:59:23 -0500860 if (kAlpha_8_SkColorType == device.colorType() && drawCoverage) {
861 SkASSERT(nullptr == shader);
862 SkASSERT(paint->isSrcOver());
863 return allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
864 }
865
Mike Kleinfb191da2016-11-15 13:20:33 -0500866 if (SkBlitter* blitter = SkCreateRasterPipelineBlitter(device, *paint, matrix, allocator)) {
mtklein9a5c47f2016-07-22 11:05:04 -0700867 return blitter;
868 }
869
halcanary96fcdcc2015-08-27 07:41:13 -0700870 if (nullptr == shader) {
reed374772b2016-10-05 17:33:02 -0700871 if (mode != SkBlendMode::kSrcOver) {
reed@google.com6b7aee32011-04-19 18:36:09 +0000872 // xfermodes (and filters) require shaders for our current blitters
reedfe630452016-03-25 09:08:00 -0700873 paint.writable()->setShader(SkShader::MakeColorShader(paint->getColor()));
commit-bot@chromium.org76a3b2a2014-04-24 16:54:46 +0000874 paint.writable()->setAlpha(0xFF);
reedfe630452016-03-25 09:08:00 -0700875 shader = paint->getShader();
reed@google.com6b7aee32011-04-19 18:36:09 +0000876 } else if (cf) {
877 // if no shader && no xfermode, we just apply the colorfilter to
878 // our color and move on.
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000879 SkPaint* writablePaint = paint.writable();
880 writablePaint->setColor(cf->filterColor(paint->getColor()));
halcanary96fcdcc2015-08-27 07:41:13 -0700881 writablePaint->setColorFilter(nullptr);
882 cf = nullptr;
reed@google.com6b7aee32011-04-19 18:36:09 +0000883 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000884 }
reed@google.com82065d62011-02-07 15:30:46 +0000885
reed@google.com6b7aee32011-04-19 18:36:09 +0000886 if (cf) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887 SkASSERT(shader);
reedd053ce92016-03-22 10:17:23 -0700888 paint.writable()->setShader(shader->makeWithColorFilter(sk_ref_sp(cf)));
reed150835e2016-03-10 06:36:49 -0800889 shader = paint->getShader();
reed@android.com1fc4c602009-10-02 16:34:57 +0000890 // blitters should ignore the presence/absence of a filter, since
891 // if there is one, the shader will take care of it.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000892 }
reed@google.com82065d62011-02-07 15:30:46 +0000893
reed@google.coma641f3f2012-12-13 22:16:30 +0000894 /*
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000895 * We create a SkShader::Context object, and store it on the blitter.
reed@google.coma641f3f2012-12-13 22:16:30 +0000896 */
halcanary96fcdcc2015-08-27 07:41:13 -0700897 SkShader::Context* shaderContext = nullptr;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000898 if (shader) {
fmalitad0c4e092016-02-22 17:19:04 -0800899 const SkShader::ContextRec rec(*paint, matrix, nullptr,
Brian Osman11970e52016-12-05 15:26:50 -0500900 PreferredShaderDest(device.info()),
901 device.colorSpace());
fmalita8d9f2e42016-02-22 10:39:41 -0800902 size_t contextSize = shader->contextSize(rec);
bsalomonb0ae6492014-12-29 07:05:27 -0800903 if (contextSize) {
904 // Try to create the ShaderContext
herbbf6d80a2016-11-15 06:26:56 -0800905 shaderContext = allocator->createWithIniter(
906 contextSize,
907 [&rec, shader](void* storage) {
908 return shader->createContext(rec, storage);
909 });
bsalomonb0ae6492014-12-29 07:05:27 -0800910 if (!shaderContext) {
bsalomonb0ae6492014-12-29 07:05:27 -0800911 return allocator->createT<SkNullBlitter>();
912 }
913 SkASSERT(shaderContext);
bsalomonb0ae6492014-12-29 07:05:27 -0800914 } else {
915 return allocator->createT<SkNullBlitter>();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000916 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000917 }
918
halcanary96fcdcc2015-08-27 07:41:13 -0700919 SkBlitter* blitter = nullptr;
reed@google.com900ecf22014-02-20 20:55:37 +0000920 switch (device.colorType()) {
921 case kAlpha_8_SkColorType:
Mike Kleine71b1672017-01-13 07:59:23 -0500922 SkASSERT(!drawCoverage); // Handled above.
923 if (shader) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000924 blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext);
reed@google.com82065d62011-02-07 15:30:46 +0000925 } else {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000926 blitter = allocator->createT<SkA8_Blitter>(device, *paint);
reed@google.com82065d62011-02-07 15:30:46 +0000927 }
928 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929
reed@google.com900ecf22014-02-20 20:55:37 +0000930 case kRGB_565_SkColorType:
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000931 blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator);
reed@google.com82065d62011-02-07 15:30:46 +0000932 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000933
commit-bot@chromium.org28fcae22014-04-11 17:15:40 +0000934 case kN32_SkColorType:
reeda34be682016-02-15 07:48:35 -0800935#ifdef SK_FORCE_PM4f_FOR_L32_BLITS
936 if (true)
937#else
reed960b2d62016-06-17 09:26:41 -0700938 if (device.info().gammaCloseToSRGB())
reeda34be682016-02-15 07:48:35 -0800939#endif
940 {
941 blitter = SkBlitter_ARGB32_Create(device, *paint, shaderContext, allocator);
reed@google.com82065d62011-02-07 15:30:46 +0000942 } else {
reeda34be682016-02-15 07:48:35 -0800943 if (shader) {
944 blitter = allocator->createT<SkARGB32_Shader_Blitter>(
945 device, *paint, shaderContext);
946 } else if (paint->getColor() == SK_ColorBLACK) {
947 blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
948 } else if (paint->getAlpha() == 0xFF) {
949 blitter = allocator->createT<SkARGB32_Opaque_Blitter>(device, *paint);
950 } else {
951 blitter = allocator->createT<SkARGB32_Blitter>(device, *paint);
952 }
reed@google.com82065d62011-02-07 15:30:46 +0000953 }
954 break;
955
reeda34be682016-02-15 07:48:35 -0800956 case kRGBA_F16_SkColorType:
reed3dc6aac2016-04-14 09:02:14 -0700957 blitter = SkBlitter_F16_Create(device, *paint, shaderContext, allocator);
reeda34be682016-02-15 07:48:35 -0800958 break;
959
reed@google.com82065d62011-02-07 15:30:46 +0000960 default:
reed@google.com82065d62011-02-07 15:30:46 +0000961 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962 }
963
reed129ed1c2016-02-22 06:42:31 -0800964 if (!blitter) {
965 blitter = allocator->createT<SkNullBlitter>();
966 }
967
reed@google.com82065d62011-02-07 15:30:46 +0000968 if (shader3D) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000969 SkBlitter* innerBlitter = blitter;
970 // innerBlitter was allocated by allocator, which will delete it.
reedcc0e3112014-09-10 10:20:24 -0700971 // We know shaderContext or its proxies is of type Sk3DShaderContext, so we need to
972 // wrapper the blitter to notify it when we see an emboss mask.
973 blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shaderContext);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 }
975 return blitter;
976}
977
reed@google.com82065d62011-02-07 15:30:46 +0000978///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979
reed56263c72015-06-05 11:31:26 -0700980class SkZeroShaderContext : public SkShader::Context {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000981public:
reed56263c72015-06-05 11:31:26 -0700982 SkZeroShaderContext(const SkShader& shader, const SkShader::ContextRec& rec)
scroggoca76c552014-06-04 08:21:01 -0700983 // Override rec with the identity matrix, so it is guaranteed to be invertible.
fmalitad0c4e092016-02-22 17:19:04 -0800984 : INHERITED(shader, SkShader::ContextRec(*rec.fPaint, SkMatrix::I(), nullptr,
Brian Osman11970e52016-12-05 15:26:50 -0500985 rec.fPreferredDstType, rec.fDstColorSpace)) {}
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000986
mtklein36352bf2015-03-25 18:17:31 -0700987 void shadeSpan(int x, int y, SkPMColor colors[], int count) override {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +0000988 sk_bzero(colors, count * sizeof(SkPMColor));
989 }
990
991private:
992 typedef SkShader::Context INHERITED;
993};
994
reed41e010c2015-06-09 12:16:53 -0700995SkShaderBlitter::SkShaderBlitter(const SkPixmap& device, const SkPaint& paint,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000996 SkShader::Context* shaderContext)
997 : INHERITED(device)
998 , fShader(paint.getShader())
999 , fShaderContext(shaderContext) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000 SkASSERT(fShader);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00001001 SkASSERT(fShaderContext);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001002
1003 fShader->ref();
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00001004 fShaderFlags = fShaderContext->getFlags();
reeda34be682016-02-15 07:48:35 -08001005 fConstInY = SkToBool(fShaderFlags & SkShader::kConstInY32_Flag);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001006}
1007
reed@android.com5119bdb2009-06-12 21:27:03 +00001008SkShaderBlitter::~SkShaderBlitter() {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001009 fShader->unref();
1010}
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00001011
commit-bot@chromium.org80116dc2014-05-06 17:16:03 +00001012bool SkShaderBlitter::resetShaderContext(const SkShader::ContextRec& rec) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00001013 // Only destroy the old context if we have a new one. We need to ensure to have a
1014 // live context in fShaderContext because the storage is owned by an SkSmallAllocator
1015 // outside of this class.
1016 // The new context will be of the same size as the old one because we use the same
1017 // shader to create it. It is therefore safe to re-use the storage.
1018 fShaderContext->~Context();
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +00001019 SkShader::Context* ctx = fShader->createContext(rec, (void*)fShaderContext);
halcanary96fcdcc2015-08-27 07:41:13 -07001020 if (nullptr == ctx) {
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +00001021 // Need a valid context in fShaderContext's storage, so we can later (or our caller) call
1022 // the in-place destructor.
halcanary385fe4d2015-08-26 13:07:48 -07001023 new (fShaderContext) SkZeroShaderContext(*fShader, rec);
commit-bot@chromium.org80116dc2014-05-06 17:16:03 +00001024 return false;
commit-bot@chromium.orgce56d962014-05-05 18:39:18 +00001025 }
commit-bot@chromium.org80116dc2014-05-06 17:16:03 +00001026 return true;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +00001027}
Mike Reed28930b42016-11-09 15:23:26 -05001028
1029///////////////////////////////////////////////////////////////////////////////////////////////////
1030
1031#ifdef SK_DEBUG
1032
1033void SkRectClipCheckBlitter::blitH(int x, int y, int width) {
1034 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1)));
1035 fBlitter->blitH(x, y, width);
1036}
1037
1038void SkRectClipCheckBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
1039 const int16_t* iter = runs;
1040 for (; *iter; iter += *iter)
1041 ;
1042 int width = iter - runs;
1043 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, 1)));
1044 fBlitter->blitAntiH(x, y, aa, runs);
1045}
1046
1047void SkRectClipCheckBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1048 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, height)));
1049 fBlitter->blitV(x, y, height, alpha);
1050}
1051
1052void SkRectClipCheckBlitter::blitRect(int x, int y, int width, int height) {
1053 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, width, height)));
1054 fBlitter->blitRect(x, y, width, height);
1055}
1056
1057void SkRectClipCheckBlitter::blitAntiRect(int x, int y, int width, int height,
1058 SkAlpha leftAlpha, SkAlpha rightAlpha) {
Yuqian Li8b9a7252016-11-11 09:40:34 -05001059 bool skipLeft = !leftAlpha;
1060 bool skipRight = !rightAlpha;
1061 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x + skipLeft, y,
1062 width + 2 - skipRight - skipLeft, height)));
Mike Reed28930b42016-11-09 15:23:26 -05001063 fBlitter->blitAntiRect(x, y, width, height, leftAlpha, rightAlpha);
1064}
1065
1066void SkRectClipCheckBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
1067 SkASSERT(mask.fBounds.contains(clip));
1068 SkASSERT(fClipRect.contains(clip));
1069 fBlitter->blitMask(mask, clip);
1070}
1071
1072const SkPixmap* SkRectClipCheckBlitter::justAnOpaqueColor(uint32_t* value) {
1073 return fBlitter->justAnOpaqueColor(value);
1074}
1075
Yuqian Li99bba9e2016-11-21 09:44:59 -05001076void SkRectClipCheckBlitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
1077 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 2, 1)));
1078 fBlitter->blitAntiH2(x, y, a0, a1);
1079}
1080
1081void SkRectClipCheckBlitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
1082 SkASSERT(fClipRect.contains(SkIRect::MakeXYWH(x, y, 1, 2)));
1083 fBlitter->blitAntiV2(x, y, a0, a1);
1084}
1085
Mike Reed28930b42016-11-09 15:23:26 -05001086#endif