xref: /aosp_15_r20/external/skia/src/core/SkDraw_text.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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