Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Typedefs | Functions | Variables
SkPDFGradientShader.cpp File Reference
#include "src/pdf/SkPDFGradientShader.h"
#include "include/core/SkTileMode.h"
#include "include/docs/SkPDFDocument.h"
#include "src/core/SkChecksum.h"
#include "src/pdf/SkPDFDocumentPriv.h"
#include "src/pdf/SkPDFFormXObject.h"
#include "src/pdf/SkPDFGraphicState.h"
#include "src/pdf/SkPDFResourceDict.h"
#include "src/pdf/SkPDFTypes.h"
#include "src/pdf/SkPDFUtils.h"

Go to the source code of this file.

Typedefs

typedef uint8_t ColorTuple[kColorComponents]
 

Functions

static uint32_t hash (const SkShaderBase::GradientInfo &v)
 
static uint32_t hash (const SkPDFGradientShader::Key &k)
 
static void unit_to_points_matrix (const SkPoint pts[2], SkMatrix *matrix)
 
static void interpolate_color_code (SkScalar range, SkColor beginColor, SkColor endColor, SkDynamicMemoryWStream *result)
 
static void write_gradient_ranges (const SkShaderBase::GradientInfo &info, SkSpan< size_t > rangeEnds, bool top, bool first, SkDynamicMemoryWStream *result)
 
static void gradient_function_code (const SkShaderBase::GradientInfo &info, SkDynamicMemoryWStream *result)
 
static std::unique_ptr< SkPDFDictcreateInterpolationFunction (const ColorTuple &color1, const ColorTuple &color2)
 
static std::unique_ptr< SkPDFDictgradientStitchCode (const SkShaderBase::GradientInfo &info)
 
static void tileModeCode (SkTileMode mode, SkDynamicMemoryWStream *result)
 
static void apply_perspective_to_coordinates (const SkMatrix &inversePerspectiveMatrix, SkDynamicMemoryWStream *code)
 
static void linearCode (const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
 
static void radialCode (const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
 
static void twoPointConicalCode (const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
 
static void sweepCode (const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
 
static void FixUpRadius (const SkPoint &p1, SkScalar &r1, const SkPoint &p2, SkScalar &r2)
 
static bool split_perspective (const SkMatrix in, SkMatrix *affine, SkMatrix *perspectiveInverse)
 
static SkPDFIndirectReference make_ps_function (std::unique_ptr< SkStreamAsset > psCode, std::unique_ptr< SkPDFArray > domain, std::unique_ptr< SkPDFObject > range, SkPDFDocument *doc)
 
static SkPDFIndirectReference make_function_shader (SkPDFDocument *doc, const SkPDFGradientShader::Key &state)
 
static SkPDFIndirectReference find_pdf_shader (SkPDFDocument *doc, SkPDFGradientShader::Key key, bool keyHasAlpha)
 
static std::unique_ptr< SkPDFDictget_gradient_resource_dict (SkPDFIndirectReference functionShader, SkPDFIndirectReference gState)
 
static std::unique_ptr< SkStreamAssetcreate_pattern_fill_content (int gsIndex, int patternIndex, SkRect &bounds)
 
static bool gradient_has_alpha (const SkPDFGradientShader::Key &key)
 
static SkPDFGradientShader::Key clone_key (const SkPDFGradientShader::Key &k)
 
static SkPDFIndirectReference create_smask_graphic_state (SkPDFDocument *doc, const SkPDFGradientShader::Key &state)
 
static SkPDFIndirectReference make_alpha_function_shader (SkPDFDocument *doc, const SkPDFGradientShader::Key &state)
 
static SkPDFGradientShader::Key make_key (const SkShader *shader, const SkMatrix &canvasTransform, const SkIRect &bbox)
 

Variables

static const int kColorComponents = 3
 

Typedef Documentation

◆ ColorTuple

typedef uint8_t ColorTuple[kColorComponents]

Definition at line 58 of file SkPDFGradientShader.cpp.

Function Documentation

◆ apply_perspective_to_coordinates()

static void apply_perspective_to_coordinates ( const SkMatrix inversePerspectiveMatrix,
SkDynamicMemoryWStream code 
)
static

Returns PS function code that applies inverse perspective to a x, y point. The function assumes that the stack has at least two elements, and that the top 2 elements are numeric values. After executing this code on a PS stack, the last 2 elements are updated while the rest of the stack is preserved intact. inversePerspectiveMatrix is the inverse perspective matrix.

Definition at line 421 of file SkPDFGradientShader.cpp.

422 {
423 if (!inversePerspectiveMatrix.hasPerspective()) {
424 return;
425 }
426
427 // Perspective matrix should be:
428 // 1 0 0
429 // 0 1 0
430 // p0 p1 p2
431
432 const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0];
433 const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1];
434 const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2];
435
436 // y = y / (p2 + p0 x + p1 y)
437 // x = x / (p2 + p0 x + p1 y)
438
439 // Input on stack: x y
440 code->writeText(" dup "); // x y y
441 SkPDFUtils::AppendScalar(p1, code); // x y y p1
442 code->writeText(" mul " // x y y*p1
443 " 2 index "); // x y y*p1 x
444 SkPDFUtils::AppendScalar(p0, code); // x y y p1 x p0
445 code->writeText(" mul "); // x y y*p1 x*p0
446 SkPDFUtils::AppendScalar(p2, code); // x y y p1 x*p0 p2
447 code->writeText(" add " // x y y*p1 x*p0+p2
448 "add " // x y y*p1+x*p0+p2
449 "3 1 roll " // y*p1+x*p0+p2 x y
450 "2 index " // z x y y*p1+x*p0+p2
451 "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2)
452 "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x
453 "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2
454 "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2)
455 "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2)
456}
static constexpr int kMPersp1
input y perspective factor
Definition SkMatrix.h:360
static constexpr int kMPersp0
input x perspective factor
Definition SkMatrix.h:359
static constexpr int kMPersp2
perspective bias
Definition SkMatrix.h:361
bool hasPerspective() const
Definition SkMatrix.h:312
float SkScalar
Definition extension.cpp:12
void AppendScalar(SkScalar value, SkWStream *stream)
Definition SkPDFUtils.h:86

◆ clone_key()

static SkPDFGradientShader::Key clone_key ( const SkPDFGradientShader::Key k)
static

Definition at line 890 of file SkPDFGradientShader.cpp.

890 {
892 k.fType,
893 k.fInfo, // change pointers later.
894 std::unique_ptr<SkColor[]>(new SkColor[k.fInfo.fColorCount]),
895 std::unique_ptr<SkScalar[]>(new SkScalar[k.fInfo.fColorCount]),
898 k.fBBox, 0};
899 clone.fInfo.fColors = clone.fColors.get();
900 clone.fInfo.fColorOffsets = clone.fStops.get();
901 for (int i = 0; i < clone.fInfo.fColorCount; i++) {
902 clone.fInfo.fColorOffsets[i] = k.fInfo.fColorOffsets[i];
903 clone.fInfo.fColors[i] = k.fInfo.fColors[i];
904 }
905 return clone;
906}
uint32_t SkColor
Definition SkColor.h:37
SkShaderBase::GradientType fType
std::unique_ptr< SkScalar[]> fStops
std::unique_ptr< SkColor[]> fColors
SkShaderBase::GradientInfo fInfo
SkColor * fColors
The colors in the gradient.
int fColorCount
In-out parameter, specifies passed size.
SkScalar * fColorOffsets
The unit offset for color transitions.

◆ create_pattern_fill_content()

static std::unique_ptr< SkStreamAsset > create_pattern_fill_content ( int  gsIndex,
int  patternIndex,
SkRect bounds 
)
static

Definition at line 866 of file SkPDFGradientShader.cpp.

868 {
870 if (gsIndex >= 0) {
872 }
873 SkPDFUtils::ApplyPattern(patternIndex, &content);
876 return content.detachAsStream();
877}
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
union flutter::testing::@2838::KeyboardChange::@76 content
void ApplyGraphicState(int objectIndex, SkWStream *content)
void AppendRectangle(const SkRect &rect, SkWStream *content)
void PaintPath(SkPaint::Style style, SkPathFillType fill, SkWStream *content)
void ApplyPattern(int objectIndex, SkWStream *content)

◆ create_smask_graphic_state()

static SkPDFIndirectReference create_smask_graphic_state ( SkPDFDocument doc,
const SkPDFGradientShader::Key state 
)
static

Definition at line 908 of file SkPDFGradientShader.cpp.

909 {
911 SkPDFGradientShader::Key luminosityState = clone_key(state);
912 for (int i = 0; i < luminosityState.fInfo.fColorCount; i++) {
913 SkAlpha alpha = SkColorGetA(luminosityState.fInfo.fColors[i]);
914 luminosityState.fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha);
915 }
916 luminosityState.fHash = hash(luminosityState);
917
918 SkASSERT(!gradient_has_alpha(luminosityState));
919 SkPDFIndirectReference luminosityShader = find_pdf_shader(doc, std::move(luminosityState), false);
920 std::unique_ptr<SkPDFDict> resources = get_gradient_resource_dict(luminosityShader,
922 SkRect bbox = SkRect::Make(state.fBBox);
923 SkPDFIndirectReference alphaMask =
925 create_pattern_fill_content(-1, luminosityShader.fValue, bbox),
927 std::move(resources),
928 SkMatrix::I(),
929 "DeviceRGB");
931 alphaMask, false, SkPDFGraphicState::kLuminosity_SMaskMode, doc);
932}
#define SkASSERT(cond)
Definition SkAssert.h:116
uint8_t SkAlpha
Definition SkColor.h:26
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColor.h:49
#define SkColorGetA(color)
Definition SkColor.h:61
SkPDFIndirectReference SkPDFMakeFormXObject(SkPDFDocument *doc, std::unique_ptr< SkStreamAsset > content, std::unique_ptr< SkPDFArray > mediaBox, std::unique_ptr< SkPDFDict > resourceDict, const SkMatrix &inverseTransform, const char *colorSpace)
static std::unique_ptr< SkPDFDict > get_gradient_resource_dict(SkPDFIndirectReference functionShader, SkPDFIndirectReference gState)
static SkPDFGradientShader::Key clone_key(const SkPDFGradientShader::Key &k)
static SkPDFIndirectReference find_pdf_shader(SkPDFDocument *doc, SkPDFGradientShader::Key key, bool keyHasAlpha)
static bool gradient_has_alpha(const SkPDFGradientShader::Key &key)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static std::unique_ptr< SkStreamAsset > create_pattern_fill_content(int gsIndex, int patternIndex, SkRect &bounds)
static const SkMatrix & I()
AtkStateType state
SkPDFIndirectReference GetSMaskGraphicState(SkPDFIndirectReference sMask, bool invert, SkPDFSMaskMode sMaskMode, SkPDFDocument *doc)
std::unique_ptr< SkPDFArray > RectToArray(const SkRect &rect)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669

◆ createInterpolationFunction()

static std::unique_ptr< SkPDFDict > createInterpolationFunction ( const ColorTuple color1,
const ColorTuple color2 
)
static

Definition at line 287 of file SkPDFGradientShader.cpp.

288 {
289 auto retval = SkPDFMakeDict();
290
291 auto c0 = SkPDFMakeArray();
292 c0->appendColorComponent(color1[0]);
293 c0->appendColorComponent(color1[1]);
294 c0->appendColorComponent(color1[2]);
295 retval->insertObject("C0", std::move(c0));
296
297 auto c1 = SkPDFMakeArray();
298 c1->appendColorComponent(color2[0]);
299 c1->appendColorComponent(color2[1]);
300 c1->appendColorComponent(color2[2]);
301 retval->insertObject("C1", std::move(c1));
302
303 retval->insertObject("Domain", SkPDFMakeArray(0, 1));
304
305 retval->insertInt("FunctionType", 2);
306 retval->insertScalar("N", 1.0f);
307
308 return retval;
309}
static std::unique_ptr< SkPDFDict > SkPDFMakeDict(const char *type=nullptr)
Definition SkPDFTypes.h:195
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition SkPDFTypes.h:135

◆ find_pdf_shader()

static SkPDFIndirectReference find_pdf_shader ( SkPDFDocument doc,
SkPDFGradientShader::Key  key,
bool  keyHasAlpha 
)
static

Definition at line 986 of file SkPDFGradientShader.cpp.

988 {
989 SkASSERT(gradient_has_alpha(key) == keyHasAlpha);
990 auto& gradientPatternMap = doc->fGradientPatternMap;
991 if (SkPDFIndirectReference* ptr = gradientPatternMap.find(key)) {
992 return *ptr;
993 }
994 SkPDFIndirectReference pdfShader;
995 if (keyHasAlpha) {
996 pdfShader = make_alpha_function_shader(doc, key);
997 } else {
998 pdfShader = make_function_shader(doc, key);
999 }
1000 gradientPatternMap.set(std::move(key), pdfShader);
1001 return pdfShader;
1002}
static SkPDFIndirectReference make_function_shader(SkPDFDocument *doc, const SkPDFGradientShader::Key &state)
static SkPDFIndirectReference make_alpha_function_shader(SkPDFDocument *doc, const SkPDFGradientShader::Key &state)
skia_private::THashMap< SkPDFGradientShader::Key, SkPDFIndirectReference, SkPDFGradientShader::KeyHash > fGradientPatternMap

◆ FixUpRadius()

static void FixUpRadius ( const SkPoint p1,
SkScalar r1,
const SkPoint p2,
SkScalar r2 
)
static

Definition at line 618 of file SkPDFGradientShader.cpp.

618 {
619 // detect touching circles
621 SkScalar subtractRadii = fabs(r1 - r2);
622 if (fabs(distance - subtractRadii) < 0.002f) {
623 if (r1 > r2) {
624 r1 += 0.002f;
625 } else {
626 r2 += 0.002f;
627 }
628 }
629}
static float Distance(const SkPoint &a, const SkPoint &b)

◆ get_gradient_resource_dict()

static std::unique_ptr< SkPDFDict > get_gradient_resource_dict ( SkPDFIndirectReference  functionShader,
SkPDFIndirectReference  gState 
)
static

Definition at line 847 of file SkPDFGradientShader.cpp.

848 {
849 std::vector<SkPDFIndirectReference> patternShaders;
850 if (functionShader != SkPDFIndirectReference()) {
851 patternShaders.push_back(functionShader);
852 }
853 std::vector<SkPDFIndirectReference> graphicStates;
854 if (gState != SkPDFIndirectReference()) {
855 graphicStates.push_back(gState);
856 }
857 return SkPDFMakeResourceDict(std::move(graphicStates),
858 std::move(patternShaders),
859 std::vector<SkPDFIndirectReference>(),
860 std::vector<SkPDFIndirectReference>());
861}
std::unique_ptr< SkPDFDict > SkPDFMakeResourceDict(const std::vector< SkPDFIndirectReference > &graphicStateResources, const std::vector< SkPDFIndirectReference > &shaderResources, const std::vector< SkPDFIndirectReference > &xObjectResources, const std::vector< SkPDFIndirectReference > &fontResources)

◆ gradient_function_code()

static void gradient_function_code ( const SkShaderBase::GradientInfo info,
SkDynamicMemoryWStream result 
)
static

Definition at line 235 of file SkPDFGradientShader.cpp.

236 {
237 // While looking for a hit the stack is [t].
238 // After finding a hit the stack is [r g b 0].
239 // The 0 is consumed just before returning.
240
241 // The initial range has no previous and contains a solid color.
242 // Any t <= 0 will be handled by this initial range, so later t == 0 indicates a hit was found.
243 result->writeText("dup 0 le {pop ");
245 result->writeText(" ");
247 result->writeText(" ");
249 result->writeText(" 0} if\n");
250
251 // Optimize out ranges which don't make any visual difference.
252 AutoSTMalloc<4, size_t> rangeEnds(info.fColorCount);
253 size_t rangeEndsCount = 0;
254 for (int i = 1; i < info.fColorCount; ++i) {
255 // Ignoring the alpha, is this range the same solid color as the next range?
256 // This optimizes gradients where sometimes only the color or only the alpha is changing.
257 auto eqIgnoringAlpha = [](SkColor a, SkColor b) {
258 return SkColorSetA(a, 0x00) == SkColorSetA(b, 0x00);
259 };
260 bool constantColorBothSides =
261 eqIgnoringAlpha(info.fColors[i-1], info.fColors[i]) &&// This range is a solid color.
262 i != info.fColorCount-1 && // This is not the last range.
263 eqIgnoringAlpha(info.fColors[i], info.fColors[i+1]); // Next range is same solid color.
264
265 // Does this range have zero size?
266 bool degenerateRange = info.fColorOffsets[i-1] == info.fColorOffsets[i];
267
268 if (!degenerateRange && !constantColorBothSides) {
269 rangeEnds[rangeEndsCount] = i;
270 ++rangeEndsCount;
271 }
272 }
273
274 // If a cap on depth is needed, loop here.
275 write_gradient_ranges(info, SkSpan(rangeEnds.get(), rangeEndsCount), true, true, result);
276
277 // Clamp the final color.
278 result->writeText("0 gt {");
279 SkPDFUtils::AppendColorComponent(SkColorGetR(info.fColors[info.fColorCount - 1]), result);
280 result->writeText(" ");
281 SkPDFUtils::AppendColorComponent(SkColorGetG(info.fColors[info.fColorCount - 1]), result);
282 result->writeText(" ");
283 SkPDFUtils::AppendColorComponent(SkColorGetB(info.fColors[info.fColorCount - 1]), result);
284 result->writeText("} if\n");
285}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SkColorGetR(color)
Definition SkColor.h:65
#define SkColorGetG(color)
Definition SkColor.h:69
static constexpr SkColor SkColorSetA(SkColor c, U8CPU a)
Definition SkColor.h:82
#define SkColorGetB(color)
Definition SkColor.h:73
static void write_gradient_ranges(const SkShaderBase::GradientInfo &info, SkSpan< size_t > rangeEnds, bool top, bool first, SkDynamicMemoryWStream *result)
static bool b
struct MyStruct a[10]
GAsyncResult * result
void AppendColorComponent(uint8_t value, SkWStream *wStream)
Definition SkPDFUtils.h:75

◆ gradient_has_alpha()

static bool gradient_has_alpha ( const SkPDFGradientShader::Key key)
static

Definition at line 879 of file SkPDFGradientShader.cpp.

879 {
881 for (int i = 0; i < key.fInfo.fColorCount; i++) {
882 if ((SkAlpha)SkColorGetA(key.fInfo.fColors[i]) != SK_AlphaOPAQUE) {
883 return true;
884 }
885 }
886 return false;
887}
constexpr SkAlpha SK_AlphaOPAQUE
Definition SkColor.h:94

◆ gradientStitchCode()

static std::unique_ptr< SkPDFDict > gradientStitchCode ( const SkShaderBase::GradientInfo info)
static

Definition at line 311 of file SkPDFGradientShader.cpp.

311 {
312 auto retval = SkPDFMakeDict();
313
314 // normalize color stops
315 int colorCount = info.fColorCount;
316 std::vector<SkColor> colors(info.fColors, info.fColors + colorCount);
317 std::vector<SkScalar> colorOffsets(info.fColorOffsets, info.fColorOffsets + colorCount);
318
319 int i = 1;
320 while (i < colorCount - 1) {
321 // ensure stops are in order
322 if (colorOffsets[i - 1] > colorOffsets[i]) {
323 colorOffsets[i] = colorOffsets[i - 1];
324 }
325
326 // remove points that are between 2 coincident points
327 if ((colorOffsets[i - 1] == colorOffsets[i]) && (colorOffsets[i] == colorOffsets[i + 1])) {
328 colorCount -= 1;
329 colors.erase(colors.begin() + i);
330 colorOffsets.erase(colorOffsets.begin() + i);
331 } else {
332 i++;
333 }
334 }
335 // find coincident points and slightly move them over
336 for (i = 1; i < colorCount - 1; i++) {
337 if (colorOffsets[i - 1] == colorOffsets[i]) {
338 colorOffsets[i] += 0.00001f;
339 }
340 }
341 // check if last 2 stops coincide
342 if (colorOffsets[i - 1] == colorOffsets[i]) {
343 colorOffsets[i - 1] -= 0.00001f;
344 }
345
346 AutoSTMalloc<4, ColorTuple> colorDataAlloc(colorCount);
347 ColorTuple *colorData = colorDataAlloc.get();
348 for (int idx = 0; idx < colorCount; idx++) {
349 colorData[idx][0] = SkColorGetR(colors[idx]);
350 colorData[idx][1] = SkColorGetG(colors[idx]);
351 colorData[idx][2] = SkColorGetB(colors[idx]);
352 }
353
354 // no need for a stitch function if there are only 2 stops.
355 if (colorCount == 2)
356 return createInterpolationFunction(colorData[0], colorData[1]);
357
358 auto encode = SkPDFMakeArray();
359 auto bounds = SkPDFMakeArray();
360 auto functions = SkPDFMakeArray();
361
362 retval->insertObject("Domain", SkPDFMakeArray(0, 1));
363 retval->insertInt("FunctionType", 3);
364
365 for (int idx = 1; idx < colorCount; idx++) {
366 if (idx > 1) {
367 bounds->appendScalar(colorOffsets[idx-1]);
368 }
369
370 encode->appendScalar(0);
371 encode->appendScalar(1.0f);
372
373 functions->appendObject(createInterpolationFunction(colorData[idx-1], colorData[idx]));
374 }
375
376 retval->insertObject("Encode", std::move(encode));
377 retval->insertObject("Bounds", std::move(bounds));
378 retval->insertObject("Functions", std::move(functions));
379
380 return retval;
381}
static void encode(uint8_t output[16], const uint32_t input[4])
Definition SkMD5.cpp:240
static std::unique_ptr< SkPDFDict > createInterpolationFunction(const ColorTuple &color1, const ColorTuple &color2)
uint8_t ColorTuple[kColorComponents]
Optional< SkRect > bounds
Definition SkRecords.h:189
PODArray< SkColor > colors
Definition SkRecords.h:276

◆ hash() [1/2]

static uint32_t hash ( const SkPDFGradientShader::Key k)
static

Definition at line 35 of file SkPDFGradientShader.cpp.

35 {
36 uint32_t buffer[] = {
37 (uint32_t)k.fType,
38 hash(k.fInfo),
42 };
43 return SkChecksum::Hash32(buffer, sizeof(buffer));
44}
static const uint8_t buffer[]
uint32_t Hash32(const void *data, size_t bytes, uint32_t seed)

◆ hash() [2/2]

static uint32_t hash ( const SkShaderBase::GradientInfo v)
static

Definition at line 22 of file SkPDFGradientShader.cpp.

22 {
23 uint32_t buffer[] = {
24 (uint32_t)v.fColorCount,
27 SkChecksum::Hash32(v.fPoint, 2 * sizeof(SkPoint)),
28 SkChecksum::Hash32(v.fRadius, 2 * sizeof(SkScalar)),
29 (uint32_t)v.fTileMode,
31 };
32 return SkChecksum::Hash32(buffer, sizeof(buffer));
33}
uint32_t fGradientFlags
see SkGradientShader::Flags
SkPoint fPoint[2]
Type specific, see above.
SkScalar fRadius[2]
Type specific, see above.

◆ interpolate_color_code()

static void interpolate_color_code ( SkScalar  range,
SkColor  beginColor,
SkColor  endColor,
SkDynamicMemoryWStream result 
)
static

Definition at line 69 of file SkPDFGradientShader.cpp.

70 {
71 SkASSERT(range != SkIntToScalar(0));
72
73 /* Linearly interpolate from the previous color to the current.
74 Scale the colors from 0..255 to 0..1 and determine the multipliers for interpolation.
75 C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}.
76 */
77
78 ColorTuple curColor = { SkTo<uint8_t>(SkColorGetR(endColor)),
79 SkTo<uint8_t>(SkColorGetG(endColor)),
80 SkTo<uint8_t>(SkColorGetB(endColor)) };
81
82 ColorTuple prevColor = { SkTo<uint8_t>(SkColorGetR(beginColor)),
83 SkTo<uint8_t>(SkColorGetG(beginColor)),
84 SkTo<uint8_t>(SkColorGetB(beginColor)) };
85
86 // Figure out how to scale each color component.
87 SkScalar multiplier[kColorComponents];
88 for (int i = 0; i < kColorComponents; i++) {
89 static const SkScalar kColorScale = SkScalarInvert(255);
90 multiplier[i] = kColorScale * (curColor[i] - prevColor[i]) / range;
91 }
92
93 // Calculate when we no longer need to keep a copy of the input parameter t.
94 // If the last component to use t is i, then dupInput[0..i - 1] = true
95 // and dupInput[i .. components] = false.
96 bool dupInput[kColorComponents];
97 dupInput[kColorComponents - 1] = false;
98 for (int i = kColorComponents - 2; i >= 0; i--) {
99 dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0;
100 }
101
102 if (!dupInput[0] && multiplier[0] == 0) {
103 result->writeText("pop ");
104 }
105
106 for (int i = 0; i < kColorComponents; i++) {
107 // If the next components needs t and this component will consume a
108 // copy, make another copy.
109 if (dupInput[i] && multiplier[i] != 0) {
110 result->writeText("dup ");
111 }
112
113 if (multiplier[i] == 0) {
115 result->writeText(" ");
116 } else {
117 if (multiplier[i] != 1) {
118 SkPDFUtils::AppendScalar(multiplier[i], result);
119 result->writeText(" mul ");
120 }
121 if (prevColor[i] != 0) {
123 result->writeText(" add ");
124 }
125 }
126
127 if (dupInput[i]) {
128 result->writeText("exch ");
129 }
130 }
131}
static const int kColorComponents
#define SkScalarInvert(x)
Definition SkScalar.h:73
#define SkIntToScalar(x)
Definition SkScalar.h:57

◆ linearCode()

static void linearCode ( const SkShaderBase::GradientInfo info,
const SkMatrix perspectiveRemover,
SkDynamicMemoryWStream function 
)
static

Definition at line 458 of file SkPDFGradientShader.cpp.

460 {
461 function->writeText("{");
462
463 apply_perspective_to_coordinates(perspectiveRemover, function);
464
465 function->writeText("pop\n"); // Just ditch the y value.
468 function->writeText("}");
469}
static void gradient_function_code(const SkShaderBase::GradientInfo &info, SkDynamicMemoryWStream *result)
static void tileModeCode(SkTileMode mode, SkDynamicMemoryWStream *result)
static void apply_perspective_to_coordinates(const SkMatrix &inversePerspectiveMatrix, SkDynamicMemoryWStream *code)
SkTileMode
Definition SkTileMode.h:13
Dart_NativeFunction function
Definition fuchsia.cc:51

◆ make_alpha_function_shader()

static SkPDFIndirectReference make_alpha_function_shader ( SkPDFDocument doc,
const SkPDFGradientShader::Key state 
)
static

Definition at line 934 of file SkPDFGradientShader.cpp.

935 {
938 for (int i = 0; i < opaqueState.fInfo.fColorCount; i++) {
939 opaqueState.fInfo.fColors[i] = SkColorSetA(opaqueState.fInfo.fColors[i], SK_AlphaOPAQUE);
940 }
941 opaqueState.fHash = hash(opaqueState);
942
943 SkASSERT(!gradient_has_alpha(opaqueState));
944 SkRect bbox = SkRect::Make(state.fBBox);
945 SkPDFIndirectReference colorShader = find_pdf_shader(doc, std::move(opaqueState), false);
946 if (!colorShader) {
947 return SkPDFIndirectReference();
948 }
949 // Create resource dict with alpha graphics state as G0 and
950 // pattern shader as P0, then write content stream.
952
953 std::unique_ptr<SkPDFDict> resourceDict = get_gradient_resource_dict(colorShader, alphaGsRef);
954
955 std::unique_ptr<SkStreamAsset> colorStream =
956 create_pattern_fill_content(alphaGsRef.fValue, colorShader.fValue, bbox);
957 std::unique_ptr<SkPDFDict> alphaFunctionShader = SkPDFMakeDict();
958 SkPDFUtils::PopulateTilingPatternDict(alphaFunctionShader.get(), bbox,
959 std::move(resourceDict), SkMatrix::I());
960 return SkPDFStreamOut(std::move(alphaFunctionShader), std::move(colorStream), doc);
961}
static SkPDFIndirectReference create_smask_graphic_state(SkPDFDocument *doc, const SkPDFGradientShader::Key &state)
SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr< SkPDFDict > dict, std::unique_ptr< SkStreamAsset > content, SkPDFDocument *doc, SkPDFSteamCompressionEnabled compress)
void PopulateTilingPatternDict(SkPDFDict *pattern, SkRect &bbox, std::unique_ptr< SkPDFDict > resources, const SkMatrix &matrix)

◆ make_function_shader()

static SkPDFIndirectReference make_function_shader ( SkPDFDocument doc,
const SkPDFGradientShader::Key state 
)
static

Definition at line 680 of file SkPDFGradientShader.cpp.

681 {
682 SkPoint transformPoints[2];
684 SkMatrix finalMatrix = state.fCanvasTransform;
685 finalMatrix.preConcat(state.fShaderTransform);
686
687 bool doStitchFunctions = (state.fType == SkShaderBase::GradientType::kLinear ||
688 state.fType == SkShaderBase::GradientType::kRadial ||
689 state.fType == SkShaderBase::GradientType::kConical) &&
690 (SkTileMode)info.fTileMode == SkTileMode::kClamp &&
691 !finalMatrix.hasPerspective();
692
693 int32_t shadingType = 1;
694 auto pdfShader = SkPDFMakeDict();
695 // The two point radial gradient further references
696 // state.fInfo
697 // in translating from x, y coordinates to the t parameter. So, we have
698 // to transform the points and radii according to the calculated matrix.
699 if (doStitchFunctions) {
700 pdfShader->insertObject("Function", gradientStitchCode(info));
701 shadingType = (state.fType == SkShaderBase::GradientType::kLinear) ? 2 : 3;
702
703 auto extend = SkPDFMakeArray();
704 extend->reserve(2);
705 extend->appendBool(true);
706 extend->appendBool(true);
707 pdfShader->insertObject("Extend", std::move(extend));
708
709 std::unique_ptr<SkPDFArray> coords;
710 if (state.fType == SkShaderBase::GradientType::kConical) {
711 SkScalar r1 = info.fRadius[0];
712 SkScalar r2 = info.fRadius[1];
713 SkPoint pt1 = info.fPoint[0];
714 SkPoint pt2 = info.fPoint[1];
715 FixUpRadius(pt1, r1, pt2, r2);
716
717 coords = SkPDFMakeArray(pt1.x(),
718 pt1.y(),
719 r1,
720 pt2.x(),
721 pt2.y(),
722 r2);
723 } else if (state.fType == SkShaderBase::GradientType::kRadial) {
724 const SkPoint& pt1 = info.fPoint[0];
725 coords = SkPDFMakeArray(pt1.x(),
726 pt1.y(),
727 0,
728 pt1.x(),
729 pt1.y(),
730 info.fRadius[0]);
731 } else {
732 const SkPoint& pt1 = info.fPoint[0];
733 const SkPoint& pt2 = info.fPoint[1];
734 coords = SkPDFMakeArray(pt1.x(),
735 pt1.y(),
736 pt2.x(),
737 pt2.y());
738 }
739
740 pdfShader->insertObject("Coords", std::move(coords));
741 } else {
742 // Depending on the type of the gradient, we want to transform the
743 // coordinate space in different ways.
744 transformPoints[0] = info.fPoint[0];
745 transformPoints[1] = info.fPoint[1];
746 switch (state.fType) {
747 case SkShaderBase::GradientType::kLinear:
748 break;
749 case SkShaderBase::GradientType::kRadial:
750 transformPoints[1] = transformPoints[0];
751 transformPoints[1].fX += info.fRadius[0];
752 break;
753 case SkShaderBase::GradientType::kConical: {
754 transformPoints[1] = transformPoints[0];
755 transformPoints[1].fX += SK_Scalar1;
756 break;
757 }
758 case SkShaderBase::GradientType::kSweep:
759 transformPoints[1] = transformPoints[0];
760 transformPoints[1].fX += SK_Scalar1;
761 break;
763 default:
764 return SkPDFIndirectReference();
765 }
766
767 // Move any scaling (assuming a unit gradient) or translation
768 // (and rotation for linear gradient), of the final gradient from
769 // info.fPoints to the matrix (updating bbox appropriately). Now
770 // the gradient can be drawn on on the unit segment.
771 SkMatrix mapperMatrix;
772 unit_to_points_matrix(transformPoints, &mapperMatrix);
773
774 finalMatrix.preConcat(mapperMatrix);
775
776 // Preserves as much as possible in the final matrix, and only removes
777 // the perspective. The inverse of the perspective is stored in
778 // perspectiveInverseOnly matrix and has 3 useful numbers
779 // (p0, p1, p2), while everything else is either 0 or 1.
780 // In this way the shader will handle it eficiently, with minimal code.
781 SkMatrix perspectiveInverseOnly = SkMatrix::I();
782 if (finalMatrix.hasPerspective()) {
783 if (!split_perspective(finalMatrix,
784 &finalMatrix, &perspectiveInverseOnly)) {
785 return SkPDFIndirectReference();
786 }
787 }
788
789 SkRect bbox;
790 bbox.set(state.fBBox);
791 if (!SkPDFUtils::InverseTransformBBox(finalMatrix, &bbox)) {
792 return SkPDFIndirectReference();
793 }
794 SkDynamicMemoryWStream functionCode;
795
797
798 if (state.fType == SkShaderBase::GradientType::kConical) {
799 SkMatrix inverseMapperMatrix;
800 if (!mapperMatrix.invert(&inverseMapperMatrix)) {
801 return SkPDFIndirectReference();
802 }
803 inverseMapperMatrix.mapPoints(infoCopy.fPoint, 2);
804 infoCopy.fRadius[0] = inverseMapperMatrix.mapRadius(info.fRadius[0]);
805 infoCopy.fRadius[1] = inverseMapperMatrix.mapRadius(info.fRadius[1]);
806 }
807 switch (state.fType) {
808 case SkShaderBase::GradientType::kLinear:
809 linearCode(infoCopy, perspectiveInverseOnly, &functionCode);
810 break;
811 case SkShaderBase::GradientType::kRadial:
812 radialCode(infoCopy, perspectiveInverseOnly, &functionCode);
813 break;
814 case SkShaderBase::GradientType::kConical:
815 twoPointConicalCode(infoCopy, perspectiveInverseOnly, &functionCode);
816 break;
817 case SkShaderBase::GradientType::kSweep:
818 sweepCode(infoCopy, perspectiveInverseOnly, &functionCode);
819 break;
820 default:
821 SkASSERT(false);
822 }
823 pdfShader->insertObject(
824 "Domain", SkPDFMakeArray(bbox.left(), bbox.right(), bbox.top(), bbox.bottom()));
825
826 auto domain = SkPDFMakeArray(bbox.left(), bbox.right(), bbox.top(), bbox.bottom());
827 std::unique_ptr<SkPDFArray> rangeObject = SkPDFMakeArray(0, 1, 0, 1, 0, 1);
828 pdfShader->insertRef("Function",
829 make_ps_function(functionCode.detachAsStream(), std::move(domain),
830 std::move(rangeObject), doc));
831 }
832
833 pdfShader->insertInt("ShadingType", shadingType);
834 pdfShader->insertName("ColorSpace", "DeviceRGB");
835
836 SkPDFDict pdfFunctionShader("Pattern");
837 pdfFunctionShader.insertInt("PatternType", 2);
838 pdfFunctionShader.insertObject("Matrix", SkPDFUtils::MatrixToArray(finalMatrix));
839 pdfFunctionShader.insertObject("Shading", std::move(pdfShader));
840 return doc->emit(pdfFunctionShader);
841}
static void radialCode(const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
static std::unique_ptr< SkPDFDict > gradientStitchCode(const SkShaderBase::GradientInfo &info)
static void sweepCode(const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
static void linearCode(const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
static bool split_perspective(const SkMatrix in, SkMatrix *affine, SkMatrix *perspectiveInverse)
static void twoPointConicalCode(const SkShaderBase::GradientInfo &info, const SkMatrix &perspectiveRemover, SkDynamicMemoryWStream *function)
static SkPDFIndirectReference make_ps_function(std::unique_ptr< SkStreamAsset > psCode, std::unique_ptr< SkPDFArray > domain, std::unique_ptr< SkPDFObject > range, SkPDFDocument *doc)
static void unit_to_points_matrix(const SkPoint pts[2], SkMatrix *matrix)
static void FixUpRadius(const SkPoint &p1, SkScalar &r1, const SkPoint &p2, SkScalar &r2)
#define SK_Scalar1
Definition SkScalar.h:18
std::unique_ptr< SkStreamAsset > detachAsStream()
Definition SkStream.cpp:876
SkScalar mapRadius(SkScalar radius) const
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition SkMatrix.cpp:770
bool invert(SkMatrix *inverse) const
Definition SkMatrix.h:1206
SkMatrix & preConcat(const SkMatrix &other)
Definition SkMatrix.cpp:674
SkPDFIndirectReference emit(const SkPDFObject &, SkPDFIndirectReference)
std::unique_ptr< SkPDFArray > MatrixToArray(const SkMatrix &matrix)
bool InverseTransformBBox(const SkMatrix &matrix, SkRect *bbox)
float fX
x-axis value
constexpr float y() const
constexpr float x() const
constexpr float left() const
Definition SkRect.h:734
constexpr float top() const
Definition SkRect.h:741
constexpr float right() const
Definition SkRect.h:748
void set(const SkIRect &src)
Definition SkRect.h:849
constexpr float bottom() const
Definition SkRect.h:755

◆ make_key()

static SkPDFGradientShader::Key make_key ( const SkShader shader,
const SkMatrix canvasTransform,
const SkIRect bbox 
)
static

Definition at line 963 of file SkPDFGradientShader.cpp.

965 {
968 {0, nullptr, nullptr, {{0, 0}, {0, 0}}, {0, 0}, SkTileMode::kClamp, 0},
969 nullptr,
970 nullptr,
971 canvasTransform,
973 bbox, 0};
974 key.fType = as_SB(shader)->asGradient(&key.fInfo);
976 SkASSERT(key.fInfo.fColorCount > 0);
977 key.fColors.reset(new SkColor[key.fInfo.fColorCount]);
978 key.fStops.reset(new SkScalar[key.fInfo.fColorCount]);
979 key.fInfo.fColors = key.fColors.get();
980 key.fInfo.fColorOffsets = key.fStops.get();
981 as_SB(shader)->asGradient(&key.fInfo);
982 key.fHash = hash(key);
983 return key;
984}
SkShaderBase * as_SB(SkShader *shader)
virtual GradientType asGradient(GradientInfo *info=nullptr, SkMatrix *localMatrix=nullptr) const
SkMatrix GetShaderLocalMatrix(const SkShader *shader)
Definition SkPDFUtils.h:117

◆ make_ps_function()

static SkPDFIndirectReference make_ps_function ( std::unique_ptr< SkStreamAsset psCode,
std::unique_ptr< SkPDFArray domain,
std::unique_ptr< SkPDFObject range,
SkPDFDocument doc 
)
static

Definition at line 669 of file SkPDFGradientShader.cpp.

672 {
673 std::unique_ptr<SkPDFDict> dict = SkPDFMakeDict();
674 dict->insertInt("FunctionType", 4);
675 dict->insertObject("Domain", std::move(domain));
676 dict->insertObject("Range", std::move(range));
677 return SkPDFStreamOut(std::move(dict), std::move(psCode), doc);
678}

◆ radialCode()

static void radialCode ( const SkShaderBase::GradientInfo info,
const SkMatrix perspectiveRemover,
SkDynamicMemoryWStream function 
)
static

Definition at line 471 of file SkPDFGradientShader.cpp.

473 {
474 function->writeText("{");
475
476 apply_perspective_to_coordinates(perspectiveRemover, function);
477
478 // Find the distance from the origin.
479 function->writeText("dup " // x y y
480 "mul " // x y^2
481 "exch " // y^2 x
482 "dup " // y^2 x x
483 "mul " // y^2 x^2
484 "add " // y^2+x^2
485 "sqrt\n"); // sqrt(y^2+x^2)
486
489 function->writeText("}");
490}

◆ split_perspective()

static bool split_perspective ( const SkMatrix  in,
SkMatrix affine,
SkMatrix perspectiveInverse 
)
static

Definition at line 633 of file SkPDFGradientShader.cpp.

634 {
635 const SkScalar p2 = in[SkMatrix::kMPersp2];
636
637 if (SkScalarNearlyZero(p2)) {
638 return false;
639 }
640
641 const SkScalar zero = SkIntToScalar(0);
642 const SkScalar one = SkIntToScalar(1);
643
644 const SkScalar sx = in[SkMatrix::kMScaleX];
645 const SkScalar kx = in[SkMatrix::kMSkewX];
646 const SkScalar tx = in[SkMatrix::kMTransX];
647 const SkScalar ky = in[SkMatrix::kMSkewY];
648 const SkScalar sy = in[SkMatrix::kMScaleY];
649 const SkScalar ty = in[SkMatrix::kMTransY];
650 const SkScalar p0 = in[SkMatrix::kMPersp0];
651 const SkScalar p1 = in[SkMatrix::kMPersp1];
652
653 // Perspective matrix would be:
654 // 1 0 0
655 // 0 1 0
656 // p0 p1 p2
657 // But we need the inverse of persp.
658 perspectiveInverse->setAll(one, zero, zero,
659 zero, one, zero,
660 -p0/p2, -p1/p2, 1/p2);
661
662 affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2,
663 ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2,
664 zero, zero, one);
665
666 return true;
667}
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:101
static constexpr int kMScaleX
horizontal scale factor
Definition SkMatrix.h:353
static constexpr int kMTransY
vertical translation
Definition SkMatrix.h:358
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition SkMatrix.h:562
static constexpr int kMTransX
horizontal translation
Definition SkMatrix.h:355
static constexpr int kMSkewY
vertical skew factor
Definition SkMatrix.h:356
static constexpr int kMScaleY
vertical scale factor
Definition SkMatrix.h:357
static constexpr int kMSkewX
horizontal skew factor
Definition SkMatrix.h:354

◆ sweepCode()

static void sweepCode ( const SkShaderBase::GradientInfo info,
const SkMatrix perspectiveRemover,
SkDynamicMemoryWStream function 
)
static

Definition at line 606 of file SkPDFGradientShader.cpp.

608 {
609 function->writeText("{exch atan 360 div\n");
612 function->writeText("}");
613}

◆ tileModeCode()

static void tileModeCode ( SkTileMode  mode,
SkDynamicMemoryWStream result 
)
static

Definition at line 384 of file SkPDFGradientShader.cpp.

384 {
385 if (mode == SkTileMode::kRepeat) {
386 result->writeText("dup truncate sub\n"); // Get the fractional part.
387 result->writeText("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1)
388 return;
389 }
390
391 if (mode == SkTileMode::kMirror) {
392 // In Preview 11.0 (1033.3) `a n mod r eq` (with a and n both integers, r integer or real)
393 // early aborts the function when false would be put on the stack.
394 // Work around this by re-writing `t 2 mod 1 eq` as `t 2 mod 0 gt`.
395
396 // Map t mod 2 into [0, 1, 1, 0].
397 // Code Stack t
398 result->writeText("abs " // +t
399 "dup " // +t.s +t.s
400 "truncate " // +t.s +t
401 "dup " // +t.s +t +t
402 "cvi " // +t.s +t +T
403 "2 mod " // +t.s +t (+T mod 2)
404 /*"1 eq "*/ "0 gt " // +t.s +t true|false
405 "3 1 roll " // true|false +t.s +t
406 "sub " // true|false 0.s
407 "exch " // 0.s true|false
408 "{1 exch sub} if\n"); // 1 - 0.s|0.s
409 }
410}

◆ twoPointConicalCode()

static void twoPointConicalCode ( const SkShaderBase::GradientInfo info,
const SkMatrix perspectiveRemover,
SkDynamicMemoryWStream function 
)
static

Definition at line 495 of file SkPDFGradientShader.cpp.

497 {
498 SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX;
499 SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY;
500 SkScalar r0 = info.fRadius[0];
501 SkScalar dr = info.fRadius[1] - info.fRadius[0];
502 SkScalar a = dx * dx + dy * dy - dr * dr;
503
504 // First compute t, if the pixel falls outside the cone, then we'll end
505 // with 'false' on the stack, otherwise we'll push 'true' with t below it
506
507 // We start with a stack of (x y), copy it and then consume one copy in
508 // order to calculate b and the other to calculate c.
509 function->writeText("{");
510
511 apply_perspective_to_coordinates(perspectiveRemover, function);
512
513 function->writeText("2 copy ");
514
515 // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr).
517 function->writeText(" mul exch ");
519 function->writeText(" mul add ");
521 function->writeText(" add -2 mul dup dup mul\n");
522
523 // c = x^2 + y^2 + radius0^2
524 function->writeText("4 2 roll dup mul exch dup mul add ");
526 function->writeText(" sub dup 4 1 roll\n");
527
528 // Contents of the stack at this point: c, b, b^2, c
529
530 // if a = 0, then we collapse to a simpler linear case
531 if (a == 0) {
532
533 // t = -c/b
534 function->writeText("pop pop div neg dup ");
535
536 // compute radius(t)
538 function->writeText(" mul ");
540 function->writeText(" add\n");
541
542 // if r(t) < 0, then it's outside the cone
543 function->writeText("0 lt {pop false} {true} ifelse\n");
544
545 } else {
546
547 // quadratic case: the Canvas spec wants the largest
548 // root t for which radius(t) > 0
549
550 // compute the discriminant (b^2 - 4ac)
552 function->writeText(" mul sub dup\n");
553
554 // if d >= 0, proceed
555 function->writeText("0 ge {\n");
556
557 // an intermediate value we'll use to compute the roots:
558 // q = -0.5 * (b +/- sqrt(d))
559 function->writeText("sqrt exch dup 0 lt {exch -1 mul} if");
560 function->writeText(" add -0.5 mul dup\n");
561
562 // first root = q / a
564 function->writeText(" div\n");
565
566 // second root = c / q
567 function->writeText("3 1 roll div\n");
568
569 // put the larger root on top of the stack
570 function->writeText("2 copy gt {exch} if\n");
571
572 // compute radius(t) for larger root
573 function->writeText("dup ");
575 function->writeText(" mul ");
577 function->writeText(" add\n");
578
579 // if r(t) > 0, we have our t, pop off the smaller root and we're done
580 function->writeText(" 0 gt {exch pop true}\n");
581
582 // otherwise, throw out the larger one and try the smaller root
583 function->writeText("{pop dup\n");
585 function->writeText(" mul ");
587 function->writeText(" add\n");
588
589 // if r(t) < 0, push false, otherwise the smaller root is our t
590 function->writeText("0 le {pop false} {true} ifelse\n");
591 function->writeText("} ifelse\n");
592
593 // d < 0, clear the stack and push false
594 function->writeText("} {pop pop pop false} ifelse\n");
595 }
596
597 // if the pixel is in the cone, proceed to compute a color
598 function->writeText("{");
601
602 // otherwise, just write black
603 function->writeText("} {0 0 0} ifelse }");
604}
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition SkRecords.h:208

◆ unit_to_points_matrix()

static void unit_to_points_matrix ( const SkPoint  pts[2],
SkMatrix matrix 
)
static

Definition at line 46 of file SkPDFGradientShader.cpp.

46 {
47 SkVector vec = pts[1] - pts[0];
48 SkScalar mag = vec.length();
49 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
50
51 vec.scale(inv);
52 matrix->setSinCos(vec.fY, vec.fX);
53 matrix->preScale(mag, mag);
54 matrix->postTranslate(pts[0].fX, pts[0].fY);
55}
static SkM44 inv(const SkM44 &m)
Definition 3d.cpp:26
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
float length() const
void scale(float scale, SkPoint *dst) const
Definition SkPoint.cpp:17
float fY
y-axis value

◆ write_gradient_ranges()

static void write_gradient_ranges ( const SkShaderBase::GradientInfo info,
SkSpan< size_t >  rangeEnds,
bool  top,
bool  first,
SkDynamicMemoryWStream result 
)
static

Definition at line 133 of file SkPDFGradientShader.cpp.

134 {
135 SkASSERT(!rangeEnds.empty());
136
137 size_t rangeEndIndex = rangeEnds[rangeEnds.size() - 1];
138 SkScalar rangeEnd = info.fColorOffsets[rangeEndIndex];
139
140 // Each range check tests 0 < t <= end.
141 if (top) {
142 SkASSERT(first);
143 // t may have been set to 0 to signal that the answer has already been found.
144 result->writeText("dup dup 0 gt exch "); // In Preview 11.0 (1033.3) `0. 0 ne` is true.
146 result->writeText(" le and {\n");
147 } else if (first) {
148 // After the top level check, only t <= end needs to be tested on if (lo) side.
149 result->writeText("dup ");
151 result->writeText(" le {\n");
152 } else {
153 // The else (hi) side.
154 result->writeText("{\n");
155 }
156
157 if (rangeEnds.size() == 1) {
158 // Set the stack to [r g b].
159 size_t rangeBeginIndex = rangeEndIndex - 1;
160 SkScalar rangeBegin = info.fColorOffsets[rangeBeginIndex];
161 SkPDFUtils::AppendScalar(rangeBegin, result);
162 result->writeText(" sub "); // consume t, put t - startOffset on the stack.
163 interpolate_color_code(rangeEnd - rangeBegin,
164 info.fColors[rangeBeginIndex], info.fColors[rangeEndIndex], result);
165 result->writeText("\n");
166 } else {
167 size_t loCount = rangeEnds.size() / 2;
168 SkSpan<size_t> loSpan = rangeEnds.subspan(0, loCount);
169 write_gradient_ranges(info, loSpan, false, true, result);
170
171 SkSpan<size_t> hiSpan = rangeEnds.subspan(loCount, rangeEnds.size() - loCount);
172 write_gradient_ranges(info, hiSpan, false, false, result);
173 }
174
175 if (top) {
176 // Put 0 on the stack for t once here instead of after every call to interpolate_color_code.
177 result->writeText("0} if\n");
178 } else if (first) {
179 result->writeText("}"); // The else (hi) side will come next.
180 } else {
181 result->writeText("} ifelse\n");
182 }
183}
static void interpolate_color_code(SkScalar range, SkColor beginColor, SkColor endColor, SkDynamicMemoryWStream *result)
constexpr SkSpan< T > subspan(size_t offset) const
constexpr bool empty() const
Definition SkSpan_impl.h:96
constexpr size_t size() const
Definition SkSpan_impl.h:95

Variable Documentation

◆ kColorComponents

const int kColorComponents = 3
static

Definition at line 57 of file SkPDFGradientShader.cpp.