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
12void SkSourceGlyphBuffer::reset() {
13 fRejectedGlyphIDs.reset();
14 fRejectedPositions.reset();
15}
16
17void 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
28void 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;
37 for (auto t : source) {
38 *packedIDCursor++ = SkPackedGlyphID{std::get<0>(t)};
39 }
40 SkDEBUGCODE(fPhase = kInput);
41}
42
43void 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;
65 for (auto [glyphID, pos] : withMappedPos) {
66 *packedIDCursor++ = SkPackedGlyphID{glyphID, pos, mask};
67 }
68 SkDEBUGCODE(fPhase = kInput);
69}
70
71SkPoint SkDrawableGlyphBuffer::startGPUDevice(
72 const SkZip<const SkGlyphID, const SkPoint>& source,
73 SkPoint origin, const SkMatrix& viewMatrix,
74 const SkGlyphPositionRoundingSpec& roundingSpec) {
75 fInputSize = source.size();
76 fDrawableSize = 0;
77
78 SkMatrix device = viewMatrix;
79 SkPoint halfSampleFreq = roundingSpec.halfAxisSampleFreq;
80 device.postTranslate(halfSampleFreq.x(), halfSampleFreq.y());
81 device.preTranslate(origin.x(), origin.y());
82
83 auto positions = source.get<1>();
84 device.mapPoints(fPositions, positions.data(), positions.size());
85
86 auto floor = [](SkPoint pt) -> SkPoint {
87 return {SkScalarFloorToScalar(pt.x()), SkScalarFloorToScalar(pt.y())};
88 };
89
90 // q = [Q](0,0,1) = [R][V][O](0,0,1).
91 SkPoint q = device.mapXY(0, 0);
92 SkPoint qFloor = floor(q);
93
94 for (auto [packedGlyphID, glyphID, pos]
95 : SkMakeZip(fMultiBuffer.get(), source.get<0>(), fPositions.get())) {
96 packedGlyphID = SkPackedGlyphID{glyphID, pos, roundingSpec.ignorePositionFieldMask};
97 pos = floor(pos - qFloor);
98 }
99
100 SkDEBUGCODE(fPhase = kInput);
101 // Return the residual = Floor(q) - q + (rx,ry,0).
102 return qFloor - q + roundingSpec.halfAxisSampleFreq;
103}
104
105
106void SkDrawableGlyphBuffer::reset() {
107 SkDEBUGCODE(fPhase = kReset);
108 if (fMaxSize > 200) {
109 fMultiBuffer.reset();
110 fPositions.reset();
111 fMaxSize = 0;
112 }
113 fInputSize = 0;
114 fDrawableSize = 0;
115}
116
117