123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/core/SkStrike.h"
- #include "include/core/SkGraphics.h"
- #include "include/core/SkPath.h"
- #include "include/core/SkTypeface.h"
- #include "include/private/SkMutex.h"
- #include "include/private/SkOnce.h"
- #include "include/private/SkTemplates.h"
- #include "src/core/SkMakeUnique.h"
- #include <cctype>
- SkStrike::SkStrike(
- const SkDescriptor& desc,
- std::unique_ptr<SkScalerContext> scaler,
- const SkFontMetrics& fontMetrics)
- : fDesc{desc}
- , fScalerContext{std::move(scaler)}
- , fFontMetrics{fontMetrics}
- , fIsSubpixel{fScalerContext->isSubpixel()}
- , fAxisAlignment{fScalerContext->computeAxisAlignmentForHText()}
- {
- SkASSERT(fScalerContext != nullptr);
- fMemoryUsed = sizeof(*this);
- }
- #ifdef SK_DEBUG
- #define VALIDATE() AutoValidate av(this)
- #else
- #define VALIDATE()
- #endif
- // -- glyph creation -------------------------------------------------------------------------------
- SkGlyph* SkStrike::makeGlyph(SkPackedGlyphID packedGlyphID) {
- fMemoryUsed += sizeof(SkGlyph);
- SkGlyph* glyph = fAlloc.make<SkGlyph>(packedGlyphID);
- fGlyphMap.set(glyph);
- return glyph;
- }
- SkGlyph* SkStrike::glyph(SkPackedGlyphID packedGlyphID) {
- VALIDATE();
- SkGlyph* glyph = fGlyphMap.findOrNull(packedGlyphID);
- if (glyph == nullptr) {
- glyph = this->makeGlyph(packedGlyphID);
- fScalerContext->getMetrics(glyph);
- }
- return glyph;
- }
- SkGlyph* SkStrike::glyph(SkGlyphID glyphID) {
- return this->glyph(SkPackedGlyphID{glyphID});
- }
- SkGlyph* SkStrike::glyph(SkGlyphID glyphID, SkPoint position) {
- const SkFixed maskX = (!fIsSubpixel || fAxisAlignment == kY_SkAxisAlignment) ? 0 : ~0;
- const SkFixed maskY = (!fIsSubpixel || fAxisAlignment == kX_SkAxisAlignment) ? 0 : ~0;
- SkFixed subX = SkScalarToFixed(position.x()) & maskX,
- subY = SkScalarToFixed(position.y()) & maskY;
- return this->glyph(SkPackedGlyphID{glyphID, subX, subY});
- }
- SkGlyph* SkStrike::glyphFromPrototype(const SkGlyphPrototype& p, void* image) {
- SkGlyph* glyph = fGlyphMap.findOrNull(p.id);
- if (glyph == nullptr) {
- fMemoryUsed += sizeof(SkGlyph);
- glyph = fAlloc.make<SkGlyph>(p);
- fGlyphMap.set(glyph);
- }
- if (glyph->setImage(&fAlloc, image)) {
- fMemoryUsed += glyph->imageSize();
- }
- return glyph;
- }
- SkGlyph* SkStrike::glyphOrNull(SkPackedGlyphID id) const {
- return fGlyphMap.findOrNull(id);
- }
- const SkPath* SkStrike::preparePath(SkGlyph* glyph) {
- if (glyph->setPath(&fAlloc, fScalerContext.get())) {
- fMemoryUsed += glyph->path()->approximateBytesUsed();
- }
- return glyph->path();
- }
- const SkPath* SkStrike::preparePath(SkGlyph* glyph, const SkPath* path) {
- if (glyph->setPath(&fAlloc, path)) {
- fMemoryUsed += glyph->path()->approximateBytesUsed();
- }
- return glyph->path();
- }
- const SkDescriptor& SkStrike::getDescriptor() const {
- return *fDesc.getDesc();
- }
- unsigned SkStrike::getGlyphCount() const {
- return fScalerContext->getGlyphCount();
- }
- int SkStrike::countCachedGlyphs() const {
- return fGlyphMap.count();
- }
- SkSpan<const SkGlyph*> SkStrike::internalPrepare(
- SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
- const SkGlyph** cursor = results;
- for (auto glyphID : glyphIDs) {
- SkGlyph* glyphPtr = this->glyph(glyphID);
- if (pathDetail == kMetricsAndPath) {
- this->preparePath(glyphPtr);
- }
- *cursor++ = glyphPtr;
- }
- return {results, glyphIDs.size()};
- }
- const void* SkStrike::prepareImage(SkGlyph* glyph) {
- if (glyph->setImage(&fAlloc, fScalerContext.get())) {
- fMemoryUsed += glyph->imageSize();
- }
- return glyph->image();
- }
- SkGlyph* SkStrike::mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) {
- SkGlyph* glyph = fGlyphMap.findOrNull(toID);
- if (glyph == nullptr) {
- glyph = this->makeGlyph(toID);
- }
- if (glyph->setMetricsAndImage(&fAlloc, from)) {
- fMemoryUsed += glyph->imageSize();
- }
- return glyph;
- }
- bool SkStrike::belongsToCache(const SkGlyph* glyph) const {
- return glyph && fGlyphMap.findOrNull(glyph->getPackedID()) == glyph;
- }
- const SkGlyph* SkStrike::getCachedGlyphAnySubPix(SkGlyphID glyphID,
- SkPackedGlyphID vetoID) const {
- for (SkFixed subY = 0; subY < SK_Fixed1; subY += SK_FixedQuarter) {
- for (SkFixed subX = 0; subX < SK_Fixed1; subX += SK_FixedQuarter) {
- SkPackedGlyphID packedGlyphID{glyphID, subX, subY};
- if (packedGlyphID == vetoID) continue;
- if (SkGlyph* glyphPtr = fGlyphMap.findOrNull(packedGlyphID)) {
- return glyphPtr;
- }
- }
- }
- return nullptr;
- }
- SkVector SkStrike::rounding() const {
- return SkStrikeCommon::PixelRounding(fIsSubpixel, fAxisAlignment);
- }
- SkSpan<const SkGlyph*> SkStrike::metrics(SkSpan<const SkGlyphID> glyphIDs,
- const SkGlyph* results[]) {
- return this->internalPrepare(glyphIDs, kMetricsOnly, results);
- }
- SkSpan<const SkGlyph*> SkStrike::preparePaths(SkSpan<const SkGlyphID> glyphIDs,
- const SkGlyph* results[]) {
- return this->internalPrepare(glyphIDs, kMetricsAndPath, results);
- }
- SkSpan<const SkGlyph*>
- SkStrike::prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
- const SkGlyph** cursor = results;
- for (auto glyphID : glyphIDs) {
- SkGlyph* glyphPtr = this->glyph(glyphID);
- (void)this->prepareImage(glyphPtr);
- *cursor++ = glyphPtr;
- }
- return {results, glyphIDs.size()};
- }
- // N.B. This glyphMetrics call culls all the glyphs which will not display based on a non-finite
- // position or that there are no mask pixels.
- SkSpan<const SkGlyphPos>
- SkStrike::prepareForDrawing(const SkPackedGlyphID packedGlyphIDs[], const SkPoint positions[],
- size_t n,
- int maxDimension, PreparationDetail detail, SkGlyphPos results[]) {
- size_t drawableGlyphCount = 0;
- for (size_t i = 0; i < n; i++) {
- SkPoint pos = positions[i];
- if (SkScalarsAreFinite(pos.x(), pos.y())) {
- SkGlyph* glyphPtr = this->glyph(packedGlyphIDs[i]);
- if (!glyphPtr->isEmpty()) {
- results[drawableGlyphCount++] = {i, glyphPtr, pos};
- if (glyphPtr->maxDimension() <= maxDimension) {
- // The glyph fits; ensure the image if needed.
- if (detail == SkStrikeInterface::kImageIfNeeded) {
- this->prepareImage(glyphPtr);
- }
- } else if (!glyphPtr->isColor()) {
- // The out of atlas glyph is not color so we can draw it using paths.
- this->preparePath(glyphPtr);
- } else {
- // This will be handled by the fallback strike.
- SkASSERT(glyphPtr->maxDimension() > maxDimension && glyphPtr->isColor());
- }
- }
- }
- }
- return SkSpan<const SkGlyphPos>{results, drawableGlyphCount};
- }
- void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
- SkGlyph* glyph, SkScalar* array, int* count) {
- glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
- }
- void SkStrike::dump() const {
- const SkTypeface* face = fScalerContext->getTypeface();
- const SkScalerContextRec& rec = fScalerContext->getRec();
- SkMatrix matrix;
- rec.getSingleMatrix(&matrix);
- matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
- SkString name;
- face->getFamilyName(&name);
- SkString msg;
- SkFontStyle style = face->fontStyle();
- msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
- face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
- rec.dump().c_str(), fGlyphMap.count());
- SkDebugf("%s\n", msg.c_str());
- }
- void SkStrike::onAboutToExitScope() { }
- #ifdef SK_DEBUG
- void SkStrike::forceValidate() const {
- size_t memoryUsed = sizeof(*this);
- fGlyphMap.foreach ([&memoryUsed](const SkGlyph* glyphPtr) {
- memoryUsed += sizeof(SkGlyph);
- if (glyphPtr->setImageHasBeenCalled()) {
- memoryUsed += glyphPtr->imageSize();
- }
- if (glyphPtr->setPathHasBeenCalled() && glyphPtr->path() != nullptr) {
- memoryUsed += glyphPtr->path()->approximateBytesUsed();
- }
- });
- SkASSERT(fMemoryUsed == memoryUsed);
- }
- void SkStrike::validate() const {
- #ifdef SK_DEBUG_GLYPH_CACHE
- forceValidate();
- #endif
- }
- #endif // SK_DEBUG
|