• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkGlyph.h"
9 
10 #include "src/core/SkArenaAlloc.h"
11 #include "src/core/SkScalerContext.h"
12 #include "src/pathops/SkPathOpsCubic.h"
13 #include "src/pathops/SkPathOpsQuad.h"
14 
15 constexpr SkIPoint SkPackedGlyphID::kXYFieldMask;
16 
mask() const17 SkMask SkGlyph::mask() const {
18     // getMetrics had to be called.
19     SkASSERT(fMaskFormat != MASK_FORMAT_UNKNOWN);
20 
21     SkMask mask;
22     mask.fImage = (uint8_t*)fImage;
23     mask.fBounds.setXYWH(fLeft, fTop, fWidth, fHeight);
24     mask.fRowBytes = this->rowBytes();
25     mask.fFormat = static_cast<SkMask::Format>(fMaskFormat);
26     return mask;
27 }
28 
mask(SkPoint position) const29 SkMask SkGlyph::mask(SkPoint position) const {
30     SkMask answer = this->mask();
31     answer.fBounds.offset(SkScalarFloorToInt(position.x()), SkScalarFloorToInt(position.y()));
32     return answer;
33 }
34 
zeroMetrics()35 void SkGlyph::zeroMetrics() {
36     fAdvanceX = 0;
37     fAdvanceY = 0;
38     fWidth    = 0;
39     fHeight   = 0;
40     fTop      = 0;
41     fLeft     = 0;
42 }
43 
bits_to_bytes(size_t bits)44 static size_t bits_to_bytes(size_t bits) {
45     return (bits + 7) >> 3;
46 }
47 
format_alignment(SkMask::Format format)48 static size_t format_alignment(SkMask::Format format) {
49     switch (format) {
50         case SkMask::kBW_Format:
51         case SkMask::kA8_Format:
52         case SkMask::k3D_Format:
53         case SkMask::kSDF_Format:
54             return alignof(uint8_t);
55         case SkMask::kARGB32_Format:
56             return alignof(uint32_t);
57         case SkMask::kLCD16_Format:
58             return alignof(uint16_t);
59         default:
60             SK_ABORT("Unknown mask format.");
61             break;
62     }
63     return 0;
64 }
65 
format_rowbytes(int width,SkMask::Format format)66 static size_t format_rowbytes(int width, SkMask::Format format) {
67     return format == SkMask::kBW_Format ? bits_to_bytes(width)
68                                         : width * format_alignment(format);
69 }
70 
formatAlignment() const71 size_t SkGlyph::formatAlignment() const {
72     return format_alignment(this->maskFormat());
73 }
74 
allocImage(SkArenaAlloc * alloc)75 size_t SkGlyph::allocImage(SkArenaAlloc* alloc) {
76     SkASSERT(!this->isEmpty());
77     auto size = this->imageSize();
78     fImage = alloc->makeBytesAlignedTo(size, this->formatAlignment());
79 
80     return size;
81 }
82 
setImage(SkArenaAlloc * alloc,SkScalerContext * scalerContext)83 bool SkGlyph::setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
84     if (!this->setImageHasBeenCalled()) {
85         // It used to be that getImage() could change the fMaskFormat. Extra checking to make
86         // sure there are no regressions.
87         SkDEBUGCODE(SkMask::Format oldFormat = this->maskFormat());
88         this->allocImage(alloc);
89         scalerContext->getImage(*this);
90         SkASSERT(oldFormat == this->maskFormat());
91         return true;
92     }
93     return false;
94 }
95 
setImage(SkArenaAlloc * alloc,const void * image)96 bool SkGlyph::setImage(SkArenaAlloc* alloc, const void* image) {
97     if (!this->setImageHasBeenCalled()) {
98         this->allocImage(alloc);
99         memcpy(fImage, image, this->imageSize());
100         return true;
101     }
102     return false;
103 }
104 
setMetricsAndImage(SkArenaAlloc * alloc,const SkGlyph & from)105 bool SkGlyph::setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from) {
106     if (fImage == nullptr) {
107         fAdvanceX = from.fAdvanceX;
108         fAdvanceY = from.fAdvanceY;
109         fWidth = from.fWidth;
110         fHeight = from.fHeight;
111         fTop = from.fTop;
112         fLeft = from.fLeft;
113         fForceBW = from.fForceBW;
114         fMaskFormat = from.fMaskFormat;
115 
116         // From glyph may not have an image because the glyph is too large.
117         return from.fImage != nullptr && this->setImage(alloc, from.image());
118     }
119     return false;
120 }
121 
rowBytes() const122 size_t SkGlyph::rowBytes() const {
123     return format_rowbytes(fWidth, (SkMask::Format)fMaskFormat);
124 }
125 
rowBytesUsingFormat(SkMask::Format format) const126 size_t SkGlyph::rowBytesUsingFormat(SkMask::Format format) const {
127     return format_rowbytes(fWidth, format);
128 }
129 
imageSize() const130 size_t SkGlyph::imageSize() const {
131     if (this->isEmpty() || this->imageTooLarge()) { return 0; }
132 
133     size_t size = this->rowBytes() * fHeight;
134 
135     if (fMaskFormat == SkMask::k3D_Format) {
136         size *= 3;
137     }
138 
139     return size;
140 }
141 
installPath(SkArenaAlloc * alloc,const SkPath * path)142 void SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path) {
143     SkASSERT(fPathData == nullptr);
144     SkASSERT(!this->setPathHasBeenCalled());
145     fPathData = alloc->make<SkGlyph::PathData>();
146     if (path != nullptr) {
147         fPathData->fPath = *path;
148         fPathData->fPath.updateBoundsCache();
149         fPathData->fPath.getGenerationID();
150         fPathData->fHasPath = true;
151     }
152 }
153 
setPath(SkArenaAlloc * alloc,SkScalerContext * scalerContext)154 bool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
155     if (!this->setPathHasBeenCalled()) {
156         SkPath path;
157         if (scalerContext->getPath(this->getPackedID(), &path)) {
158             this->installPath(alloc, &path);
159         } else {
160             this->installPath(alloc, nullptr);
161         }
162         return this->path() != nullptr;
163     }
164 
165     return false;
166 }
167 
setPath(SkArenaAlloc * alloc,const SkPath * path)168 bool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path) {
169     if (!this->setPathHasBeenCalled()) {
170         this->installPath(alloc, path);
171         return this->path() != nullptr;
172     }
173     return false;
174 }
175 
path() const176 const SkPath* SkGlyph::path() const {
177     // setPath must have been called previously.
178     SkASSERT(this->setPathHasBeenCalled());
179     if (fPathData->fHasPath) {
180         return &fPathData->fPath;
181     }
182     return nullptr;
183 }
184 
calculate_path_gap(SkScalar topOffset,SkScalar bottomOffset,const SkPath & path)185 static std::tuple<SkScalar, SkScalar> calculate_path_gap(
186         SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
187 
188     // Left and Right of an ever expanding gap around the path.
189     SkScalar left  = SK_ScalarMax,
190              right = SK_ScalarMin;
191     auto expandGap = [&left, &right](SkScalar v) {
192         left  = std::min(left, v);
193         right = std::max(right, v);
194     };
195 
196     // Handle all the different verbs for the path.
197     SkPoint pts[4];
198     auto addLine = [&expandGap, &pts](SkScalar offset) {
199         SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY);
200         if (0 <= t && t < 1) {   // this handles divide by zero above
201             expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
202         }
203     };
204 
205     auto addQuad = [&expandGap, &pts](SkScalar offset) {
206         SkDQuad quad;
207         quad.set(pts);
208         double roots[2];
209         int count = quad.horizontalIntersect(offset, roots);
210         while (--count >= 0) {
211             expandGap(quad.ptAtT(roots[count]).asSkPoint().fX);
212         }
213     };
214 
215     auto addCubic = [&expandGap, &pts](SkScalar offset) {
216         SkDCubic cubic;
217         cubic.set(pts);
218         double roots[3];
219         int count = cubic.horizontalIntersect(offset, roots);
220         while (--count >= 0) {
221             expandGap(cubic.ptAtT(roots[count]).asSkPoint().fX);
222         }
223     };
224 
225     // Handle when a verb's points are in the gap between top and bottom.
226     auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) {
227         for (int i = 0; i < ptCount; ++i) {
228             if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) {
229                 expandGap(pts[i].fX);
230             }
231         }
232     };
233 
234     SkPath::Iter iter(path, false);
235     SkPath::Verb verb;
236     while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
237         switch (verb) {
238             case SkPath::kMove_Verb: {
239                 break;
240             }
241             case SkPath::kLine_Verb: {
242                 addLine(topOffset);
243                 addLine(bottomOffset);
244                 addPts(2);
245                 break;
246             }
247             case SkPath::kQuad_Verb: {
248                 SkScalar quadTop = std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY);
249                 if (bottomOffset < quadTop) { break; }
250                 SkScalar quadBottom = std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY);
251                 if (topOffset > quadBottom) { break; }
252                 addQuad(topOffset);
253                 addQuad(bottomOffset);
254                 addPts(3);
255                 break;
256             }
257             case SkPath::kConic_Verb: {
258                 SkASSERT(0);  // no support for text composed of conics
259                 break;
260             }
261             case SkPath::kCubic_Verb: {
262                 SkScalar quadTop =
263                         std::min(std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
264                 if (bottomOffset < quadTop) { break; }
265                 SkScalar quadBottom =
266                         std::max(std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
267                 if (topOffset > quadBottom) { break; }
268                 addCubic(topOffset);
269                 addCubic(bottomOffset);
270                 addPts(4);
271                 break;
272             }
273             case SkPath::kClose_Verb: {
274                 break;
275             }
276             default: {
277                 SkASSERT(0);
278                 break;
279             }
280         }
281     }
282 
283     return std::tie(left, right);
284 }
285 
ensureIntercepts(const SkScalar * bounds,SkScalar scale,SkScalar xPos,SkScalar * array,int * count,SkArenaAlloc * alloc)286 void SkGlyph::ensureIntercepts(const SkScalar* bounds, SkScalar scale, SkScalar xPos,
287                                SkScalar* array, int* count, SkArenaAlloc* alloc) {
288 
289     auto offsetResults = [scale, xPos](
290             const SkGlyph::Intercept* intercept,SkScalar* array, int* count) {
291         if (array) {
292             array += *count;
293             for (int index = 0; index < 2; index++) {
294                 *array++ = intercept->fInterval[index] * scale + xPos;
295             }
296         }
297         *count += 2;
298     };
299 
300     const SkGlyph::Intercept* match =
301             [this](const SkScalar bounds[2]) -> const SkGlyph::Intercept* {
302                 if (!fPathData) {
303                     return nullptr;
304                 }
305                 const SkGlyph::Intercept* intercept = fPathData->fIntercept;
306                 while (intercept) {
307                     if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
308                         return intercept;
309                     }
310                     intercept = intercept->fNext;
311                 }
312                 return nullptr;
313             }(bounds);
314 
315     if (match) {
316         if (match->fInterval[0] < match->fInterval[1]) {
317             offsetResults(match, array, count);
318         }
319         return;
320     }
321 
322     SkGlyph::Intercept* intercept = alloc->make<SkGlyph::Intercept>();
323     intercept->fNext = fPathData->fIntercept;
324     intercept->fBounds[0] = bounds[0];
325     intercept->fBounds[1] = bounds[1];
326     intercept->fInterval[0] = SK_ScalarMax;
327     intercept->fInterval[1] = SK_ScalarMin;
328     fPathData->fIntercept = intercept;
329     const SkPath* path = &(fPathData->fPath);
330     const SkRect& pathBounds = path->getBounds();
331     if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) {
332         return;
333     }
334 
335     std::tie(intercept->fInterval[0], intercept->fInterval[1])
336             = calculate_path_gap(bounds[0], bounds[1], *path);
337 
338     if (intercept->fInterval[0] >= intercept->fInterval[1]) {
339         intercept->fInterval[0] = SK_ScalarMax;
340         intercept->fInterval[1] = SK_ScalarMin;
341         return;
342     }
343     offsetResults(intercept, array, count);
344 }
345