1/*
2 * Copyright 2018 Google Inc.
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
8#include "src/core/SkDraw.h"
9#include "src/core/SkFontPriv.h"
10#include "src/core/SkMatrixProvider.h"
11#include "src/core/SkPaintPriv.h"
12#include "src/core/SkRasterClip.h"
13#include "src/core/SkScalerCache.h"
14#include "src/core/SkScalerContext.h"
15#include "src/core/SkUtils.h"
16#include <climits>
17
18// disable warning : local variable used without having been initialized
19#if defined _WIN32
20#pragma warning ( push )
21#pragma warning ( disable : 4701 )
22#endif
23
24////////////////////////////////////////////////////////////////////////////////////////////////////
25
26static bool check_glyph_position(SkPoint position) {
27 // Prevent glyphs from being drawn outside of or straddling the edge of device space.
28 // Comparisons written a little weirdly so that NaN coordinates are treated safely.
29 auto gt = [](float a, int b) { return !(a <= (float)b); };
30 auto lt = [](float a, int b) { return !(a >= (float)b); };
31 return !(gt(position.fX, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) ||
32 lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) ||
33 gt(position.fY, INT_MAX - (INT16_MAX + SkTo<int>(UINT16_MAX))) ||
34 lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)));
35}
36
37void SkDraw::paintMasks(SkDrawableGlyphBuffer* drawables, const SkPaint& paint) const {
38
39 // The size used for a typical blitter.
40 SkSTArenaAlloc<3308> alloc;
41 SkBlitter* blitter =
42 SkBlitter::Choose(fDst, *fMatrixProvider, paint, &alloc, false, fRC->clipShader());
43 if (fCoverage) {
44 blitter = alloc.make<SkPairBlitter>(
45 blitter,
46 SkBlitter::Choose(
47 *fCoverage, *fMatrixProvider, SkPaint(), &alloc, true, fRC->clipShader()));
48 }
49
50 SkAAClipBlitterWrapper wrapper{*fRC, blitter};
51 blitter = wrapper.getBlitter();
52
53 bool useRegion = fRC->isBW() && !fRC->isRect();
54
55 if (useRegion) {
56 for (auto [variant, pos] : drawables->drawable()) {
57 SkGlyph* glyph = variant.glyph();
58 if (check_glyph_position(pos)) {
59 SkMask mask = glyph->mask(pos);
60
61 SkRegion::Cliperator clipper(fRC->bwRgn(), mask.fBounds);
62
63 if (!clipper.done()) {
64 if (SkMask::kARGB32_Format == mask.fFormat) {
65 SkBitmap bm;
66 bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.size()),
67 mask.fImage,
68 mask.fRowBytes);
69 this->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), paint);
70 } else {
71 const SkIRect& cr = clipper.rect();
72 do {
73 blitter->blitMask(mask, cr);
74 clipper.next();
75 } while (!clipper.done());
76 }
77 }
78 }
79 }
80 } else {
81 SkIRect clipBounds = fRC->isBW() ? fRC->bwRgn().getBounds()
82 : fRC->aaRgn().getBounds();
83 for (auto [variant, pos] : drawables->drawable()) {
84 SkGlyph* glyph = variant.glyph();
85 if (check_glyph_position(pos)) {
86 SkMask mask = glyph->mask(pos);
87 SkIRect storage;
88 const SkIRect* bounds = &mask.fBounds;
89
90 // this extra test is worth it, assuming that most of the time it succeeds
91 // since we can avoid writing to storage
92 if (!clipBounds.containsNoEmptyCheck(mask.fBounds)) {
93 if (!storage.intersect(mask.fBounds, clipBounds)) {
94 continue;
95 }
96 bounds = &storage;
97 }
98
99 if (SkMask::kARGB32_Format == mask.fFormat) {
100 SkBitmap bm;
101 bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.size()),
102 mask.fImage,
103 mask.fRowBytes);
104 this->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), paint);
105 } else {
106 blitter->blitMask(mask, *bounds);
107 }
108 }
109 }
110 }
111}
112
113void SkDraw::paintPaths(SkDrawableGlyphBuffer* drawables,
114 SkScalar scale,
115 SkPoint origin,
116 const SkPaint& paint) const {
117 for (auto [variant, pos] : drawables->drawable()) {
118 const SkPath* path = variant.path();
119 SkMatrix m;
120 SkPoint translate = origin + pos;
121 m.setScaleTranslate(scale, scale, translate.x(), translate.y());
122 this->drawPath(*path, paint, &m, false);
123 }
124}
125
126void SkDraw::drawGlyphRunList(const SkGlyphRunList& glyphRunList,
127 SkGlyphRunListPainter* glyphPainter) const {
128
129 SkDEBUGCODE(this->validate();)
130
131 if (fRC->isEmpty()) {
132 return;
133 }
134
135 glyphPainter->drawForBitmapDevice(glyphRunList, fMatrixProvider->localToDevice(), this);
136}
137
138#if defined _WIN32
139#pragma warning ( pop )
140#endif
141
142