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