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