Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/skia/skia/src/core/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 14 kB image not shown  

Quelle  SkStrike.cpp   Sprache: C

 
/*
 * 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/SkDrawable.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
#include "include/core/SkString.h"
#include "include/core/SkTraceMemoryDump.h"
#include "include/core/SkTypeface.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkTFitsIn.h"
#include "src/core/SkGlyph.h"
#include "src/core/SkMask.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkScalerContext.h"
#include "src/core/SkStrikeCache.h"
#include "src/core/SkWriteBuffer.h"
#include "src/text/StrikeForGPU.h"

#include <cctype>
#include <new>
#include <optional>
#include <utility>

using namespace skglyph;

static SkFontMetrics use_or_generate_metrics(
        const SkFontMetrics* metrics, SkScalerContext* context) {
    SkFontMetrics answer;
    if (metrics) {
        answer = *metrics;
    } else {
        context->getFontMetrics(&answer);
    }
    return answer;
}

SkStrike::SkStrike(SkStrikeCache* strikeCache,
                   const SkStrikeSpec& strikeSpec,
                   std::unique_ptr<SkScalerContext> scaler,
                   const SkFontMetrics* metrics,
                   std::unique_ptr<SkStrikePinner> pinner)
        : fFontMetrics{use_or_generate_metrics(metrics, scaler.get())}
        , fRoundingSpec{scaler->isSubpixel(),
                        scaler->computeAxisAlignmentForHText()}
        , fStrikeSpec{strikeSpec}
        , fStrikeCache{strikeCache}
        , fScalerContext{std::move(scaler)}
        , fPinner{std::move(pinner)} {
    SkASSERT(fScalerContext != nullptr);
}

class SK_SCOPED_CAPABILITY SkStrike::Monitor {
public:
    Monitor(SkStrike* strike) SK_ACQUIRE(strike->fStrikeLock)
            : fStrike{strike} {
        fStrike->lock();
    }

    ~Monitor() SK_RELEASE_CAPABILITY() {
        fStrike->unlock();
    }

private:
    SkStrike* const fStrike;
};

void SkStrike::lock() {
    fStrikeLock.acquire();
    fMemoryIncrease = 0;
}

void SkStrike::unlock() {
    const size_t memoryIncrease = fMemoryIncrease;
    fStrikeLock.release();
    this->updateMemoryUsage(memoryIncrease);
}

void
SkStrike::FlattenGlyphsByType(SkWriteBuffer& buffer,
                              SkSpan<SkGlyph> images,
                              SkSpan<SkGlyph> paths,
                              SkSpan<SkGlyph> drawables) {
    SkASSERT_RELEASE(SkTFitsIn<int>(images.size()) &&
                     SkTFitsIn<int>(paths.size()) &&
                     SkTFitsIn<int>(drawables.size()));

    buffer.writeInt(images.size());
    for (SkGlyph& glyph : images) {
        SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
        glyph.flattenMetrics(buffer);
        glyph.flattenImage(buffer);
    }

    buffer.writeInt(paths.size());
    for (SkGlyph& glyph : paths) {
        SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
        glyph.flattenMetrics(buffer);
        glyph.flattenPath(buffer);
    }

    buffer.writeInt(drawables.size());
    for (SkGlyph& glyph : drawables) {
        SkASSERT(SkMask::IsValidFormat(glyph.maskFormat()));
        glyph.flattenMetrics(buffer);
        glyph.flattenDrawable(buffer);
    }
}

bool SkStrike::mergeFromBuffer(SkReadBuffer& buffer) {
    // Read glyphs with images for the current strike.
    const int imagesCount = buffer.readInt();
    if (imagesCount == 0 && !buffer.isValid()) {
        return false;
    }

    {
        Monitor m{this};
        for (int curImage = 0; curImage < imagesCount; ++curImage) {
            if (!this->mergeGlyphAndImageFromBuffer(buffer)) {
                return false;
            }
        }
    }

    // Read glyphs with paths for the current strike.
    const int pathsCount = buffer.readInt();
    if (pathsCount == 0 && !buffer.isValid()) {
        return false;
    }
    {
        Monitor m{this};
        for (int curPath = 0; curPath < pathsCount; ++curPath) {
            if (!this->mergeGlyphAndPathFromBuffer(buffer)) {
                return false;
            }
        }
    }

    // Read glyphs with drawables for the current strike.
    const int drawablesCount = buffer.readInt();
    if (drawablesCount == 0 && !buffer.isValid()) {
        return false;
    }
    {
        Monitor m{this};
        for (int curDrawable = 0; curDrawable < drawablesCount; ++curDrawable) {
            if (!this->mergeGlyphAndDrawableFromBuffer(buffer)) {
                return false;
            }
        }
    }

    return true;
}

SkGlyph* SkStrike::mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& fromGlyph) {
    Monitor m{this};
    // TODO(herb): remove finding the glyph when setting the metrics and image are separated
    SkGlyphDigest* digest = fDigestForPackedGlyphID.find(toID);
    if (digest != nullptr) {
        SkGlyph* glyph = fGlyphForIndex[digest->index()];
        if (fromGlyph.setImageHasBeenCalled()) {
            if (glyph->setImageHasBeenCalled()) {
                // Should never set an image on a glyph which already has an image.
                SkDEBUGFAIL("Re-adding image to existing glyph. This should not happen.");
            }
            // TODO: assert that any metrics on fromGlyph are the same.
            fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph);
        }
        return glyph;
    } else {
        SkGlyph* glyph = fAlloc.make<SkGlyph>(toID);
        fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph) + sizeof(SkGlyph);
        (void)this->addGlyphAndDigest(glyph);
        return glyph;
    }
}

const SkPath* SkStrike::mergePath(SkGlyph* glyph, const SkPath* path, bool hairline, bool modified) {
    Monitor m{this};
    if (glyph->setPathHasBeenCalled()) {
        SkDEBUGFAIL("Re-adding path to existing glyph. This should not happen.");
    }
    if (glyph->setPath(&fAlloc, path, hairline, modified)) {
        fMemoryIncrease += glyph->path()->approximateBytesUsed();
    }

    return glyph->path();
}

const SkDrawable* SkStrike::mergeDrawable(SkGlyph* glyph, sk_sp<SkDrawable> drawable) {
    Monitor m{this};
    if (glyph->setDrawableHasBeenCalled()) {
        SkDEBUGFAIL("Re-adding drawable to existing glyph. This should not happen.");
    }
    if (glyph->setDrawable(&fAlloc, std::move(drawable))) {
        fMemoryIncrease += glyph->drawable()->approximateBytesUsed();
        SkASSERT(fMemoryIncrease > 0);
    }

    return glyph->drawable();
}

void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
                              SkGlyph* glyph, SkScalar* array, int* count) {
    SkAutoMutexExclusive lock{fStrikeLock};
    glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
}

SkSpan<const SkGlyph*> SkStrike::metrics(
        SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
    Monitor m{this};
    return this->internalPrepare(glyphIDs, kMetricsOnly, results);
}

SkSpan<const SkGlyph*> SkStrike::preparePaths(
        SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
    Monitor m{this};
    return this->internalPrepare(glyphIDs, kMetricsAndPath, results);
}

SkSpan<const SkGlyph*> SkStrike::prepareImages(
        SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
    const SkGlyph** cursor = results;
    Monitor m{this};
    for (auto glyphID : glyphIDs) {
        SkGlyph* glyph = this->glyph(glyphID);
        this->prepareForImage(glyph);
        *cursor++ = glyph;
    }

    return {results, glyphIDs.size()};
}

SkSpan<const SkGlyph*> SkStrike::prepareDrawables(
        SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
    const SkGlyph** cursor = results;
    {
        Monitor m{this};
        for (auto glyphID : glyphIDs) {
            SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
            this->prepareForDrawable(glyph);
            *cursor++ = glyph;
        }
    }

    return {results, glyphIDs.size()};
}

void SkStrike::glyphIDsToPaths(SkSpan<sktext::IDOrPath> idsOrPaths) {
    Monitor m{this};
    for (sktext::IDOrPath& idOrPath : idsOrPaths) {
        SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrPath.fGlyphID});
        this->prepareForPath(glyph);
        new (&idOrPath.fPath) SkPath{*glyph->path()};
    }
}

void SkStrike::glyphIDsToDrawables(SkSpan<sktext::IDOrDrawable> idsOrDrawables) {
    Monitor m{this};
    for (sktext::IDOrDrawable& idOrDrawable : idsOrDrawables) {
        SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrDrawable.fGlyphID});
        this->prepareForDrawable(glyph);
        SkASSERT(glyph->drawable() != nullptr);
        idOrDrawable.fDrawable = glyph->drawable();
    }
}

void SkStrike::dump() const {
    SkAutoMutexExclusive lock{fStrikeLock};
    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(), fDigestForPackedGlyphID.count());
    SkDebugf("%s\n", msg.c_str());
}

void SkStrike::dumpMemoryStatistics(SkTraceMemoryDump* dump) const {
    SkAutoMutexExclusive lock{fStrikeLock};
    const SkTypeface* face = fScalerContext->getTypeface();
    const SkScalerContextRec& rec = fScalerContext->getRec();

    SkString fontName;
    face->getFamilyName(&fontName);
    // Replace all special characters with '_'.
    for (size_t index = 0; index < fontName.size(); ++index) {
        if (!std::isalnum(fontName[index])) {
            fontName[index] = '_';
        }
    }

    SkString dumpName = SkStringPrintf("%s/%s_%u/%p",
                                       SkStrikeCache::kGlyphCacheDumpName,
                                       fontName.c_str(),
                                       rec.fTypefaceID,
                                       this);

    dump->dumpNumericValue(dumpName.c_str(), "size""bytes", fMemoryUsed);
    dump->dumpNumericValue(dumpName.c_str(),
                           "glyph_count""objects",
                           fDigestForPackedGlyphID.count());
    dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
}

SkGlyph* SkStrike::glyph(SkGlyphDigest digest) {
    return fGlyphForIndex[digest.index()];
}

SkGlyph* SkStrike::glyph(SkPackedGlyphID packedGlyphID) {
    SkGlyphDigest digest = this->digestFor(kDirectMask, packedGlyphID);
    return this->glyph(digest);
}

SkGlyphDigest SkStrike::digestFor(ActionType actionType, SkPackedGlyphID packedGlyphID) {
    SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(packedGlyphID);
    if (digestPtr != nullptr && digestPtr->actionFor(actionType) != GlyphAction::kUnset) {
        return *digestPtr;
    }

    SkGlyph* glyph;
    if (digestPtr != nullptr) {
        glyph = fGlyphForIndex[digestPtr->index()];
    } else {
        glyph = fAlloc.make<SkGlyph>(fScalerContext->makeGlyph(packedGlyphID, &fAlloc));
        fMemoryIncrease += sizeof(SkGlyph);
        digestPtr = this->addGlyphAndDigest(glyph);
    }

    digestPtr->setActionFor(actionType, glyph, this);

    return *digestPtr;
}

SkGlyphDigest* SkStrike::addGlyphAndDigest(SkGlyph* glyph) {
    size_t index = fGlyphForIndex.size();
    SkGlyphDigest digest = SkGlyphDigest{index, *glyph};
    SkGlyphDigest* newDigest = fDigestForPackedGlyphID.set(digest);
    fGlyphForIndex.push_back(glyph);
    return newDigest;
}

bool SkStrike::prepareForImage(SkGlyph* glyph) {
    if (glyph->setImage(&fAlloc, fScalerContext.get())) {
        fMemoryIncrease += glyph->imageSize();
    }
    return glyph->image() != nullptr;
}

bool SkStrike::prepareForPath(SkGlyph* glyph) {
    if (glyph->setPath(&fAlloc, fScalerContext.get())) {
        fMemoryIncrease += glyph->path()->approximateBytesUsed();
    }
    return glyph->path() !=nullptr;
}

bool SkStrike::prepareForDrawable(SkGlyph* glyph) {
    if (glyph->setDrawable(&fAlloc, fScalerContext.get())) {
        size_t increase = glyph->drawable()->approximateBytesUsed();
        SkASSERT(increase > 0);
        fMemoryIncrease += increase;
    }
    return glyph->drawable() != nullptr;
}

SkGlyph* SkStrike::mergeGlyphFromBuffer(SkReadBuffer& buffer) {
    SkASSERT(buffer.isValid());
    std::optional<SkGlyph> prototypeGlyph = SkGlyph::MakeFromBuffer(buffer);
    if (!buffer.validate(prototypeGlyph.has_value())) {
        return nullptr;
    }

    // Check if this glyph has already been seen.
    SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(prototypeGlyph->getPackedID());
    if (digestPtr != nullptr) {
        return fGlyphForIndex[digestPtr->index()];
    }

    // This is the first time. Allocate a new glyph.
    SkGlyph* glyph = fAlloc.make<SkGlyph>(prototypeGlyph.value());
    fMemoryIncrease += sizeof(SkGlyph);
    this->addGlyphAndDigest(glyph);
    return glyph;
}

bool SkStrike::mergeGlyphAndImageFromBuffer(SkReadBuffer& buffer) {
    SkASSERT(buffer.isValid());
    SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
    if (!buffer.validate(glyph != nullptr)) {
        return false;
    }
    fMemoryIncrease += glyph->addImageFromBuffer(buffer, &fAlloc);
    return buffer.isValid();
}

bool SkStrike::mergeGlyphAndPathFromBuffer(SkReadBuffer& buffer) {
    SkASSERT(buffer.isValid());
    SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
    if (!buffer.validate(glyph != nullptr)) {
        return false;
    }
    fMemoryIncrease += glyph->addPathFromBuffer(buffer, &fAlloc);
    return buffer.isValid();
}

bool SkStrike::mergeGlyphAndDrawableFromBuffer(SkReadBuffer& buffer) {
    SkASSERT(buffer.isValid());
    SkGlyph* glyph = this->mergeGlyphFromBuffer(buffer);
    if (!buffer.validate(glyph != nullptr)) {
        return false;
    }
    fMemoryIncrease += glyph->addDrawableFromBuffer(buffer, &fAlloc);
    return buffer.isValid();
}

SkSpan<const SkGlyph*> SkStrike::internalPrepare(
        SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
    const SkGlyph** cursor = results;
    for (auto glyphID : glyphIDs) {
        SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
        if (pathDetail == kMetricsAndPath) {
            this->prepareForPath(glyph);
        }
        *cursor++ = glyph;
    }

    return {results, glyphIDs.size()};
}

void SkStrike::updateMemoryUsage(size_t increase) {
    if (increase > 0) {
        // fRemoved and the cache's total memory are managed under the cache's lock. This allows
        // them to be accessed under LRU operation.
        SkAutoMutexExclusive lock{fStrikeCache->fLock};
        fMemoryUsed += increase;
        if (!fRemoved) {
            fStrikeCache->fTotalMemoryUsed += increase;
        }
    }
}

Messung V0.5
C=98 H=88 G=93

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.