blob: bd216b2840274bc603fe236853ba6ee18f162255 [file] [log] [blame]
Julia Lavrova5207f352019-06-21 12:22:32 -04001// Copyright 2019 Google LLC.
Julia Lavrova5207f352019-06-21 12:22:32 -04002#include "modules/skparagraph/src/ParagraphCache.h"
Mike Klein52337de2019-07-25 09:00:52 -05003#include "modules/skparagraph/src/ParagraphImpl.h"
Julia Lavrova5207f352019-06-21 12:22:32 -04004
5namespace skia {
6namespace textlayout {
7
8// Just the flutter input for now
9// TODO: We don't really need to copy anything...
10ParagraphCacheKey::ParagraphCacheKey(ParagraphImpl* paragraph)
11 : fText(paragraph->fText)
12 , fFontSwitches(paragraph->switches())
13 , fTextStyles(paragraph->fTextStyles)
14 , fParagraphStyle(paragraph->paragraphStyle()) { }
15
16// TODO: copying clusters and runs for now (there are minor things changed on formatting)
17ParagraphCacheValue::ParagraphCacheValue(ParagraphImpl* paragraph)
18 : fKey(ParagraphCacheKey(paragraph))
19 , fInternalState(paragraph->state())
20 , fRuns(paragraph->fRuns)
21 , fClusters(paragraph->fClusters)
22 , fMeasurement(paragraph->measurement())
23 , fPicture(paragraph->fPicture) { }
24
25bool ParagraphCache::findParagraph(ParagraphImpl* paragraph) {
26
27 SkAutoMutexExclusive lock(fParagraphMutex);
28 if (this->count() == 0) {
29 return false;
30 }
31
32 ParagraphCacheKey key(paragraph);
33 auto found = this->find(key);
34 if (found == nullptr) {
35 fChecker(paragraph, "findParagraph", false);
36 return false;
37 }
38 paragraph->fRuns.reset();
39 paragraph->fRuns = found->fRuns;
40 for (auto& run : paragraph->fRuns) {
41 run.setMaster(paragraph);
42 }
43
44 paragraph->fClusters.reset();
45 paragraph->fClusters = found->fClusters;
46 for (auto& cluster : paragraph->fClusters) {
47 cluster.setMaster(paragraph);
48 }
49
50 paragraph->fLines.reset();
51 for (auto& line : found->fLines) {
52 paragraph->fLines.push_back(line);
53 paragraph->fLines.back().setMaster(paragraph);
54 }
55
56 paragraph->fState = found->fInternalState;
57 paragraph->setMeasurement(found->fMeasurement);
58
59 paragraph->fOldWidth = found->fMeasurement.fWidth;
60 paragraph->fOldHeight = found->fMeasurement.fHeight;
61
62 paragraph->fPicture = found->fPicture;
63
64 fChecker(paragraph, "findParagraph", true);
65 return true;
66}
67
68void ParagraphCache::addParagraph(ParagraphImpl* paragraph) {
69
70 SkAutoMutexExclusive lock(fParagraphMutex);
71 auto value = new ParagraphCacheValue(paragraph);
72 this->add(value);
73 fChecker(paragraph, "addParagraph1", true);
74}
75
76void ParagraphCache::updateParagraph(ParagraphImpl* paragraph) {
77
78 SkAutoMutexExclusive lock(fParagraphMutex);
79 ParagraphCacheKey key(paragraph);
80 auto found = this->find(key);
81 if (found != nullptr) {
82 found->fInternalState = paragraph->fState;
83 found->fMeasurement = paragraph->measurement();
84 found->fLines = paragraph->fLines;
85 for (size_t i = 0; i < paragraph->fRuns.size(); ++i) {
86 auto& run = paragraph->fRuns[i];
87 if (run.fSpaced) {
88 found->fRuns[i] = run;
89 }
90 }
91 found->fPicture = paragraph->fPicture;
92 fChecker(paragraph, "updateParagraph", true);
93 } else {
94 auto value = new ParagraphCacheValue(paragraph);
95 this->add(value);
96 fChecker(paragraph, "addParagraph2", true);
97 }
98}
99
100const ParagraphCacheKey& LookupTrait::GetKey(const ParagraphCacheValue& paragraph) {
101 return paragraph.fKey;
102}
103
104bool operator==(const ParagraphCacheKey& a, const ParagraphCacheKey& b) {
105 if (a.fText.size() != b.fText.size()) {
106 return false;
107 }
108 if (a.fFontSwitches.count() != b.fFontSwitches.count()) {
109 return false;
110 }
111 if (a.fText != b.fText) {
112 return false;
113 }
114 if (a.fTextStyles.size() != b.fTextStyles.size()) {
115 return false;
116 }
117
118 if (a.fParagraphStyle.getMaxLines() != b.fParagraphStyle.getMaxLines()) {
119 // TODO: this is too strong, but at least we will not lose lines
120 return false;
121 }
122
123 for (size_t i = 0; i < a.fFontSwitches.size(); ++i) {
124 auto& fda = a.fFontSwitches[i];
125 auto& fdb = b.fFontSwitches[i];
126 if (fda.fStart != fdb.fStart) {
127 return false;
128 }
129 if (fda.fFont != fdb.fFont) {
130 return false;
131 }
132 }
133
134 for (size_t i = 0; i < a.fTextStyles.size(); ++i) {
135 auto& tsa = a.fTextStyles[i];
136 auto& tsb = b.fTextStyles[i];
137 if (tsa.fStyle.getLetterSpacing() != tsb.fStyle.getLetterSpacing()) {
138 return false;
139 }
140 if (tsa.fStyle.getWordSpacing() != tsb.fStyle.getWordSpacing()) {
141 return false;
142 }
143 if (tsa.fRange.width() != tsb.fRange.width()) {
144 return false;
145 }
146 if (tsa.fRange.start != tsb.fRange.start) {
147 return false;
148 }
149 }
150
151 return true;
152}
153
154uint32_t LookupTrait::mix(uint32_t hash, uint32_t data) {
155 hash += data;
156 hash += (hash << 10);
157 hash ^= (hash >> 6);
158 return hash;
159}
160
161uint32_t LookupTrait::Hash(const ParagraphCacheKey& key) {
162 uint32_t hash = 0;
163 for (auto& fd : key.fFontSwitches) {
164 hash = mix(hash, SkGoodHash()(fd.fStart));
165 hash = mix(hash, SkGoodHash()(fd.fFont.getSize()));
166
167 if (fd.fFont.getTypeface() != nullptr) {
168 SkString name;
169 fd.fFont.getTypeface()->getFamilyName(&name);
170 hash = mix(hash, SkGoodHash()(name));
171 hash = mix(hash, SkGoodHash()(fd.fFont.getTypeface()->fontStyle()));
172 }
173 }
174 for (auto& ts : key.fTextStyles) {
175 hash = mix(hash, SkGoodHash()(ts.fStyle.getLetterSpacing()));
176 hash = mix(hash, SkGoodHash()(ts.fStyle.getWordSpacing()));
177 }
178 hash = mix(hash, SkGoodHash()(key.fText));
179 return hash;
180}
181
182void ParagraphCache::printCache(const char* title) {
183
184 SkDebugf("\n\n%s\n", title);
185 SkTDynamicHash<ParagraphCacheValue, ParagraphCacheKey, LookupTrait>::Iter iter(this);
186 while (!iter.done()) {
187 ParagraphCacheValue* v = &*iter;
188 const ParagraphCacheKey& k = LookupTrait::GetKey(*v);
189 SkDebugf("key: '%s' runs(%d) clusters(%d)\n", k.fText.c_str(), v->fRuns.size(), v->fClusters.size());
190 ++iter;
191 }
192}
193
194void ParagraphCache::printKeyValue(const char* title, ParagraphImpl* paragraph, bool found) {
195 /*
196 SkDebugf("%s '%s' ", title, paragraph->text().data());
197 for (auto& fd : paragraph->switches()) {
198 SkDebugf("%d ", fd.fFont.getTypeface() != nullptr ? fd.fFont.getTypeface()->uniqueID(): 0);
199 };
200 SkDebugf("\n");
201 */
202}
203
204}
205}