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