1 /*
2  * Copyright 2019 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/SkGlyphBuffer.h"
9 #include "src/core/SkGlyphRunPainter.h"
10 #include "src/core/SkStrikeForGPU.h"
11 
reset()12 void SkSourceGlyphBuffer::reset() {
13     fRejectedGlyphIDs.reset();
14     fRejectedPositions.reset();
15 }
16 
ensureSize(size_t size)17 void SkDrawableGlyphBuffer::ensureSize(size_t size) {
18     if (size > fMaxSize) {
19         fMultiBuffer.reset(size);
20         fPositions.reset(size);
21         fMaxSize = size;
22     }
23 
24     fInputSize = 0;
25     fDrawableSize = 0;
26 }
27 
startSource(const SkZip<const SkGlyphID,const SkPoint> & source)28 void SkDrawableGlyphBuffer::startSource(const SkZip<const SkGlyphID, const SkPoint>& source) {
29     fInputSize = source.size();
30     fDrawableSize = 0;
31 
32     auto positions = source.get<1>();
33     memcpy(fPositions, positions.data(), positions.size() * sizeof(SkPoint));
34 
35     // Convert from SkGlyphIDs to SkPackedGlyphIDs.
36     SkGlyphVariant* packedIDCursor = fMultiBuffer.get();
37     for (auto t : source) {
38         *packedIDCursor++ = SkPackedGlyphID{std::get<0>(t)};
39     }
40     SkDEBUGCODE(fPhase = kInput);
41 }
42 
startBitmapDevice(const SkZip<const SkGlyphID,const SkPoint> & source,SkPoint origin,const SkMatrix & viewMatrix,const SkGlyphPositionRoundingSpec & roundingSpec)43 void SkDrawableGlyphBuffer::startBitmapDevice(
44         const SkZip<const SkGlyphID, const SkPoint>& source,
45         SkPoint origin, const SkMatrix& viewMatrix,
46         const SkGlyphPositionRoundingSpec& roundingSpec) {
47     fInputSize = source.size();
48     fDrawableSize = 0;
49 
50     // Map the positions including subpixel position.
51     auto positions = source.get<1>();
52     SkMatrix matrix = viewMatrix;
53     matrix.preTranslate(origin.x(), origin.y());
54     SkPoint halfSampleFreq = roundingSpec.halfAxisSampleFreq;
55     matrix.postTranslate(halfSampleFreq.x(), halfSampleFreq.y());
56     matrix.mapPoints(fPositions, positions.data(), positions.size());
57 
58     // Mask for controlling axis alignment.
59     SkIPoint mask = roundingSpec.ignorePositionFieldMask;
60 
61     // Convert glyph ids and positions to packed glyph ids.
62     SkZip<const SkGlyphID, const SkPoint> withMappedPos =
63             SkMakeZip(source.get<0>(), fPositions.get());
64     SkGlyphVariant* packedIDCursor = fMultiBuffer.get();
65     for (auto [glyphID, pos] : withMappedPos) {
66         *packedIDCursor++ = SkPackedGlyphID{glyphID, pos, mask};
67     }
68     SkDEBUGCODE(fPhase = kInput);
69 }
70 
startGPUDevice(const SkZip<const SkGlyphID,const SkPoint> & source,const SkMatrix & drawMatrix,const SkGlyphPositionRoundingSpec & roundingSpec)71 void SkDrawableGlyphBuffer::startGPUDevice(
72         const SkZip<const SkGlyphID, const SkPoint>& source,
73         const SkMatrix& drawMatrix,
74         const SkGlyphPositionRoundingSpec& roundingSpec) {
75     fInputSize = source.size();
76     fDrawableSize = 0;
77 
78     // Build up the mapping from source space to device space. Add the rounding constant
79     // halfSampleFreq so we just need to floor to get the device result.
80     SkMatrix device = drawMatrix;
81     SkPoint halfSampleFreq = roundingSpec.halfAxisSampleFreq;
82     device.postTranslate(halfSampleFreq.x(), halfSampleFreq.y());
83 
84     auto positions = source.get<1>();
85     device.mapPoints(fPositions, positions.data(), positions.size());
86 
87     auto floor = [](SkPoint pt) -> SkPoint {
88         return {SkScalarFloorToScalar(pt.x()), SkScalarFloorToScalar(pt.y())};
89     };
90 
91     for (auto [packedGlyphID, glyphID, pos]
92             : SkMakeZip(fMultiBuffer.get(), source.get<0>(), fPositions.get())) {
93         packedGlyphID = SkPackedGlyphID{glyphID, pos, roundingSpec.ignorePositionFieldMask};
94         // Store rounded device coords back in pos.
95         pos = floor(pos);
96     }
97 
98     SkDEBUGCODE(fPhase = kInput);
99 }
100 
dumpInput() const101 SkString SkDrawableGlyphBuffer::dumpInput() const {
102     SkASSERT(fPhase == kInput);
103 
104     SkString msg;
105     for (auto [packedGlyphID, pos]
106             : SkZip<SkGlyphVariant, SkPoint>{fInputSize, fMultiBuffer.get(), fPositions.get()}) {
107         msg.appendf("0x%x:(%a,%a), ", packedGlyphID.packedID().value(), pos.x(), pos.y());
108     }
109     return msg;
110 }
111 
reset()112 void SkDrawableGlyphBuffer::reset() {
113     SkDEBUGCODE(fPhase = kReset);
114     if (fMaxSize > 200) {
115         fMultiBuffer.reset();
116         fPositions.reset();
117         fMaxSize = 0;
118     }
119     fInputSize = 0;
120     fDrawableSize = 0;
121 }
122 
123