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/SkScalerCache.h"
13#include "src/core/SkScalerContext.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
25static 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
36void 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, fRC->clipShader());
41 if (fCoverage) {
42 blitter = alloc.make<SkPairBlitter>(
43 blitter,
44 SkBlitter::Choose(*fCoverage, *fMatrix, SkPaint(), &alloc, true, fRC->clipShader()));
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 [variant, pos] : drawables->drawable()) {
54 SkGlyph* glyph = variant.glyph();
55 if (check_glyph_position(pos)) {
56 SkMask mask = glyph->mask(pos);
57
58 SkRegion::Cliperator clipper(fRC->bwRgn(), mask.fBounds);
59
60 if (!clipper.done()) {
61 if (SkMask::kARGB32_Format == mask.fFormat) {
62 SkBitmap bm;
63 bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.size()),
64 mask.fImage,
65 mask.fRowBytes);
66 this->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), paint);
67 } else {
68 const SkIRect& cr = clipper.rect();
69 do {
70 blitter->blitMask(mask, cr);
71 clipper.next();
72 } while (!clipper.done());
73 }
74 }
75 }
76 }
77 } else {
78 SkIRect clipBounds = fRC->isBW() ? fRC->bwRgn().getBounds()
79 : fRC->aaRgn().getBounds();
80 for (auto [variant, pos] : drawables->drawable()) {
81 SkGlyph* glyph = variant.glyph();
82 if (check_glyph_position(pos)) {
83 SkMask mask = glyph->mask(pos);
84 SkIRect storage;
85 const SkIRect* bounds = &mask.fBounds;
86
87 // this extra test is worth it, assuming that most of the time it succeeds
88 // since we can avoid writing to storage
89 if (!clipBounds.containsNoEmptyCheck(mask.fBounds)) {
90 if (!storage.intersect(mask.fBounds, clipBounds)) {
91 continue;
92 }
93 bounds = &storage;
94 }
95
96 if (SkMask::kARGB32_Format == mask.fFormat) {
97 SkBitmap bm;
98 bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.size()),
99 mask.fImage,
100 mask.fRowBytes);
101 this->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), paint);
102 } else {
103 blitter->blitMask(mask, *bounds);
104 }
105 }
106 }
107 }
108}
109
110void SkDraw::paintPaths(SkDrawableGlyphBuffer* drawables,
111 SkScalar scale,
112 const SkPaint& paint) const {
113 for (auto [variant, pos] : drawables->drawable()) {
114 const SkPath* path = variant.path();
115 SkMatrix m;
116 m.setScaleTranslate(scale, scale, pos.x(), pos.y());
117 this->drawPath(*path, paint, &m, false);
118 }
119}
120
121void SkDraw::drawGlyphRunList(const SkGlyphRunList& glyphRunList,
122 SkGlyphRunListPainter* glyphPainter) const {
123
124 SkDEBUGCODE(this->validate();)
125
126 if (fRC->isEmpty()) {
127 return;
128 }
129
130 glyphPainter->drawForBitmapDevice(glyphRunList, *fMatrix, this);
131}
132
133#if defined _WIN32
134#pragma warning ( pop )
135#endif
136
137