Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/skia/skia/src/core/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 8 kB image not shown  

Quelle  SkPath_serial.cpp

  Sprache: C
 

/*
 * Copyright 2018 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "include/core/SkData.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/private/SkPathRef.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkPoint_impl.h"
#include "include/private/base/SkTPin.h"
#include "include/private/base/SkTo.h"
#include "src/base/SkAutoMalloc.h"
#include "src/base/SkBuffer.h"
#include "src/base/SkSafeMath.h"
#include "src/core/SkPathEnums.h"
#include "src/core/SkPathPriv.h"
#include "src/core/SkRRectPriv.h"

#include <cstddef>
#include <cstdint>
#include <optional>

enum SerializationOffsets {
    kType_SerializationShift = 28,       // requires 4 bits
    kDirection_SerializationShift = 26,  // requires 2 bits
    kFillType_SerializationShift = 8,    // requires 8 bits
    // low-8-bits are version
    kVersion_SerializationMask = 0xFF,
};

enum SerializationVersions {
    // kPathPrivFirstDirection_Version = 1,
    // kPathPrivLastMoveToIndex_Version = 2,
    // kPathPrivTypeEnumVersion = 3,
    kJustPublicData_Version = 4,            // introduced Feb/2018
    kVerbsAreStoredForward_Version = 5,     // introduced Sept/2019

    kMin_Version     = kJustPublicData_Version,
    kCurrent_Version = kVerbsAreStoredForward_Version
};

enum SerializationType {
    kGeneral = 0,
    kRRect = 1
};

static unsigned extract_version(uint32_t packed) {
    return packed & kVersion_SerializationMask;
}

static SkPathFillType extract_filltype(uint32_t packed) {
    return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3);
}

static SerializationType extract_serializationtype(uint32_t packed) {
    return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

size_t SkPath::writeToMemoryAsRRect(void* storage) const {
    SkRRect rrect;
    SkPathDirection firstDir;
    unsigned start;

    if (auto oinfo = this->getOvalInfo()) {
        rrect.setOval(oinfo->fBounds);
        firstDir = oinfo->fDirection;
        // Convert to rrect start indices.
        start = oinfo->fStartIndex * 2;
    } else if (auto rinfo = this->getRRectInfo()) {
        rrect = rinfo->fRRect;
        firstDir = rinfo->fDirection;
        start = rinfo->fStartIndex;
    } else {
        return 0;
    }

    // packed header, rrect, start index.
    const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
    if (!storage) {
        return sizeNeeded;
    }

    int32_t packed = (static_cast<int>(fFillType) << kFillType_SerializationShift) |
                     ((int)firstDir << kDirection_SerializationShift) |
                     (SerializationType::kRRect << kType_SerializationShift) |
                     kCurrent_Version;

    SkWBuffer buffer(storage);
    buffer.write32(packed);
    SkRRectPriv::WriteToBuffer(rrect, &buffer);
    buffer.write32(SkToS32(start));
    buffer.padToAlign4();
    SkASSERT(sizeNeeded == buffer.pos());
    return buffer.pos();
}

size_t SkPath::writeToMemory(void* storage) const {
    SkDEBUGCODE(this->validate();)

    if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
        return bytes;
    }

    int32_t packed = (static_cast<int>(fFillType) << kFillType_SerializationShift) |
                     (SerializationType::kGeneral << kType_SerializationShift) |
                     kCurrent_Version;

    SkSpan<const SkPoint> points = this->points();
    SkSpan<const SkPathVerb> verbs = this->verbs();
    SkSpan<const float> conics = this->conicWeights();

    int32_t pts = SkToS32(points.size());
    int32_t cnx = SkToS32(conics.size());
    int32_t vbs = SkToS32(verbs.size());

    SkSafeMath safe;
    size_t size = 4 * sizeof(int32_t);
    size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
    size = safe.add(size, safe.mul(cnx, sizeof(float)));
    size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
    size = safe.alignUp(size, 4);
    if (!safe) {
        return 0;
    }
    if (!storage) {
        return size;
    }

    SkWBuffer buffer(storage);
    buffer.write32(packed);
    buffer.write32(pts);
    buffer.write32(cnx);
    buffer.write32(vbs);
    buffer.write(points.data(), points.size_bytes());
    buffer.write(conics.data(), conics.size_bytes());
    buffer.write(verbs.data(), verbs.size_bytes());
    buffer.padToAlign4();

    SkASSERT(buffer.pos() == size);
    return size;
}

sk_sp<SkData> SkPath::serialize() const {
    size_t size = this->writeToMemory(nullptr);
    sk_sp<SkData> data = SkData::MakeUninitialized(size);
    this->writeToMemory(data->writable_data());
    return data;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// reading

std::optional<SkPath> read_rrect_path(const void* storage, size_t length, size_t* bytesRead) {
    SkASSERT(bytesRead);
    SkRBuffer buffer(storage, length);
    uint32_t packed;
    if (!buffer.readU32(&packed)) {
        *bytesRead = 0;
        return {};
    }

    SkASSERT(extract_serializationtype(packed) == SerializationType::kRRect);

    uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
    SkPathFillType fillType = extract_filltype(packed);

    SkPathDirection rrectDir;
    switch (dir) {
        case (int)SkPathFirstDirection::kCW:
            rrectDir = SkPathDirection::kCW;
            break;
        case (int)SkPathFirstDirection::kCCW:
            rrectDir = SkPathDirection::kCCW;
            break;
        default:
            *bytesRead = 0;
            return {};
    }

    SkRRect rrect;
    if (!SkRRectPriv::ReadFromBuffer(&buffer, &rrect)) {
        *bytesRead = 0;
        return {};
    }

    int32_t start;
    if (!buffer.readS32(&start) || start != SkTPin(start, 07)) {
        *bytesRead = 0;
        return {};
    }

    SkPath path = SkPath::RRect(rrect, rrectDir, SkToUInt(start));
    path.setFillType(fillType);
    buffer.skipToAlign4();
    *bytesRead = buffer.pos();
    return path;
}

std::optional<SkPath> SkPath::ReadFromMemory(const void* storage, size_t length, size_t* bytesRead) {
    size_t bytesStorage = 0;
    if (!bytesRead) {
        bytesRead = &bytesStorage;
    }
    SkRBuffer buffer(storage, length);
    uint32_t packed;
    if (!buffer.readU32(&packed)) {
        *bytesRead = 0;
        return {};
    }
    unsigned version = extract_version(packed);

    const bool verbsAreForward = (version == kVerbsAreStoredForward_Version);
    if (!verbsAreForward && version != kJustPublicData_Version) SK_UNLIKELY {
        // Old/unsupported version.
        *bytesRead = 0;
        return {};
    }

    switch (extract_serializationtype(packed)) {
        case SerializationType::kRRect:
            return read_rrect_path(storage, length, bytesRead);
        case SerializationType::kGeneral:
            break;  // fall out
        default:
            *bytesRead = 0;
            return {};
    }

    // To minimize the number of reads done a structure with the counts is used.
    struct {
      uint32_t pts, cnx, vbs;
    } counts;
    if (!buffer.read(&counts, sizeof(counts))) {
        *bytesRead = 0;
        return {};
    }

    const SkPoint* points = buffer.skipCount<SkPoint>(counts.pts);
    const SkScalar* conics = buffer.skipCount<SkScalar>(counts.cnx);
    const SkPathVerb* verbs = buffer.skipCount<SkPathVerb>(counts.vbs);
    buffer.skipToAlign4();
    if (!buffer.isValid()) {
        *bytesRead = 0;
        return {};
    }
    SkASSERT(buffer.pos() <= length);

    if (counts.vbs == 0) {
        if (counts.pts == 0 && counts.cnx == 0) {
            SkPath path(extract_filltype(packed));
            *bytesRead = buffer.pos();
            return path;
        }
        // No verbs but points and/or conic weights is a not a valid path.
        *bytesRead = 0;
        return {};
    }

    SkAutoMalloc reversedStorage;
    if (!verbsAreForward) SK_UNLIKELY {
        SkPathVerb* tmpVerbs = (SkPathVerb*)reversedStorage.reset(counts.vbs);
        for (unsigned i = 0; i < counts.vbs; ++i) {
            tmpVerbs[i] = verbs[counts.vbs - i - 1];
        }
        verbs = tmpVerbs;
    }

    *bytesRead = buffer.pos();
    return SkPath::Raw({points, counts.pts},
                       {verbs, counts.vbs},
                       {conics, counts.cnx},
                       extract_filltype(packed),
                       false);
}

Messung V0.5 in Prozent
C=89 H=99 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-08-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.