26 return x ==
y || (
x !=
x &&
y !=
y);
34 : fText(paragraph->fText.c_str(), paragraph->fText.size())
35 , fPlaceholders(paragraph->fPlaceholders)
36 , fTextStyles(paragraph->fTextStyles)
37 , fParagraphStyle(paragraph->paragraphStyle()) {
38 fHash = computeHash();
44 : fText(
std::move(other.fText))
45 , fPlaceholders(
std::move(other.fPlaceholders))
46 , fTextStyles(
std::move(other.fTextStyles))
47 , fParagraphStyle(
std::move(other.fParagraphStyle))
48 , fHash(other.fHash) {
54 uint32_t
hash()
const {
return fHash; }
59 static uint32_t mix(uint32_t
hash, uint32_t data);
60 uint32_t computeHash()
const;
99uint32_t ParagraphCacheKey::mix(uint32_t
hash, uint32_t data) {
106uint32_t ParagraphCacheKey::computeHash()
const {
108 for (
auto& ph : fPlaceholders) {
109 if (ph.fRange.width() == 0) {
122 for (
auto& ts : fTextStyles) {
123 if (ts.fStyle.isPlaceholder()) {
131 for (
auto& ff : ts.
fStyle.getFontFamilies()) {
134 for (
auto& ff : ts.
fStyle.getFontFeatures()) {
138 hash = mix(
hash, std::hash<std::optional<FontArguments>>()(ts.fStyle.getFontArguments()));
149 if (strutStyle.getStrutEnabled()) {
156 for (
auto& ff : strutStyle.getFontFamilies()) {
165uint32_t ParagraphCache::KeyHash::operator()(
const ParagraphCacheKey&
key)
const {
170 if (fText.
size() != other.fText.
size()) {
173 if (fPlaceholders.size() != other.fPlaceholders.size()) {
176 if (fText != other.fText) {
179 if (fTextStyles.size() != other.fTextStyles.size()) {
199 for (
int i = 0; i < fTextStyles.size(); ++i) {
200 auto& tsa = fTextStyles[i];
201 auto& tsb = other.fTextStyles[i];
202 if (tsa.fStyle.isPlaceholder()) {
205 if (!(tsa.fStyle.equalsByFonts(tsb.fStyle))) {
208 if (tsa.fRange.width() != tsb.fRange.width()) {
211 if (tsa.fRange.start != tsb.fRange.start) {
215 for (
int i = 0; i < fPlaceholders.size(); ++i) {
216 auto& tsa = fPlaceholders[i];
217 auto& tsb = other.fPlaceholders[i];
218 if (tsa.fRange.width() == 0 && tsb.fRange.width() == 0) {
221 if (!(tsa.fStyle.equals(tsb.fStyle))) {
224 if (tsa.fRange.width() != tsb.fRange.width()) {
227 if (tsa.fRange.start != tsb.fRange.start) {
238 std::unique_ptr<ParagraphCacheValue>
fValue;
243 , fLRUCacheMap(kMaxEntries)
245 , fLastCachedValue(
nullptr)
246#ifdef PARAGRAPH_CACHE_STATS
255void ParagraphCache::updateTo(
ParagraphImpl* paragraph,
const Entry* entry) {
257 paragraph->fRuns.clear();
258 paragraph->fRuns = entry->fValue->fRuns;
259 paragraph->fClusters = entry->fValue->fClusters;
260 paragraph->fClustersIndexFromCodeUnit = entry->fValue->fClustersIndexFromCodeUnit;
261 paragraph->fCodeUnitProperties = entry->fValue->fCodeUnitProperties;
262 paragraph->fWords = entry->fValue->fWords;
263 paragraph->fBidiRegions = entry->fValue->fBidiRegions;
264 paragraph->fHasLineBreaks = entry->fValue->fHasLineBreaks;
265 paragraph->fHasWhitespacesInside = entry->fValue->fHasWhitespacesInside;
266 paragraph->fTrailingSpaces = entry->fValue->fTrailingSpaces;
267 for (
auto&
run : paragraph->fRuns) {
268 run.setOwner(paragraph);
270 for (
auto& cluster : paragraph->fClusters) {
271 cluster.setOwner(paragraph);
276 SkDebugf(
"--- Paragraph Cache ---\n");
277 SkDebugf(
"Total requests: %d\n", fTotalRequests);
278 SkDebugf(
"Cache misses: %d\n", fCacheMisses);
279 SkDebugf(
"Cache miss %%: %f\n", (fTotalRequests > 0) ? 100.f * fCacheMisses / fTotalRequests : 0.f);
280 int cacheHits = fTotalRequests - fCacheMisses;
281 SkDebugf(
"Hash miss %%: %f\n", (cacheHits > 0) ? 100.f * fHashMisses / cacheHits : 0.f);
282 SkDebugf(
"---------------------\n");
291#ifdef PARAGRAPH_CACHE_STATS
296 fLRUCacheMap.reset();
297 fLastCachedValue =
nullptr;
304#ifdef PARAGRAPH_CACHE_STATS
309 std::unique_ptr<Entry>* entry = fLRUCacheMap.find(
key);
313#ifdef PARAGRAPH_CACHE_STATS
316 fChecker(paragraph,
"missingParagraph",
true);
319 updateTo(paragraph, entry->get());
320 fChecker(paragraph,
"foundParagraph",
true);
328#ifdef PARAGRAPH_CACHE_STATS
334 std::unique_ptr<Entry>* entry = fLRUCacheMap.find(
key);
342 fLRUCacheMap.insert(
value->fKey, std::make_unique<Entry>(
value));
343 fChecker(paragraph,
"addedParagraph",
true);
344 fLastCachedValue =
value;
353#define NOCACHE_PREFIX_LENGTH 40
355 if (fLastCachedValue ==
nullptr) {
359 auto& lastText = fLastCachedValue->
fKey.
text();
360 auto&
text = paragraph->fText;
SkStrokeRec::Style fStyle
#define NOCACHE_PREFIX_LENGTH
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static uint32_t SkFloat2Bits(float value)
static bool SkIsFinite(T x, Pack... values)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
#define SkScalarRoundToScalar(x)
ParagraphCacheKey(const ParagraphImpl *paragraph)
ParagraphCacheKey(const ParagraphCacheKey &other)=default
const SkString & text() const
bool operator==(const ParagraphCacheKey &other) const
ParagraphCacheKey(ParagraphCacheKey &&other)
TArray< size_t, true > fClustersIndexFromCodeUnit
TArray< SkUnicode::CodeUnitFlags, true > fCodeUnitProperties
TextIndex fTrailingSpaces
std::vector< size_t > fWords
TArray< Cluster, true > fClusters
std::vector< SkUnicode::BidiRegion > fBidiRegions
TArray< Run, false > fRuns
bool fHasWhitespacesInside
ParagraphCacheValue(ParagraphCacheKey &&key, const ParagraphImpl *paragraph)
bool updateParagraph(ParagraphImpl *paragraph)
bool findParagraph(ParagraphImpl *paragraph)
bool isPossiblyTextEditing(ParagraphImpl *paragraph)
@ kBaseline
Match the baseline of the placeholder with the baseline.
std::unique_ptr< ParagraphCacheValue > fValue
Entry(ParagraphCacheValue *value)
SkScalar getHeight() const
bool getReplaceTabCharacters() const
const StrutStyle & getStrutStyle() const
TextDirection getTextDirection() const