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 12 kB image not shown  

Quelle  SkCanvasPriv.cpp   Sprache: C

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


#include "src/core/SkCanvasPriv.h"

#include "include/core/SkBlendMode.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkImageFilter.h"
#include "include/core/SkMaskFilter.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkShader.h"
#include "include/private/base/SkAlign.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkTo.h"
#include "src/base/SkAutoMalloc.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/core/SkWriter32.h"

#include <utility>
#include <cstdint>

SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
                                                 const SkPaint* paint, const SkRect& bounds)
        : fCanvas(canvas)
        , fSaveCount(canvas->getSaveCount()) {
    if (paint) {
        SkRect newBounds = bounds;
        if (matrix) {
            matrix->mapRect(&newBounds);
        }
        canvas->saveLayer(&newBounds, paint);
    } else if (matrix) {
        canvas->save();
    }

    if (matrix) {
        canvas->concat(*matrix);
    }
}

SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
    fCanvas->restoreToCount(fSaveCount);
}

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

bool SkCanvasPriv::ReadLattice(SkReadBuffer& buffer, SkCanvas::Lattice* lattice) {
    lattice->fXCount = buffer.readInt();
    lattice->fXDivs = buffer.skipT<int32_t>(lattice->fXCount);
    lattice->fYCount = buffer.readInt();
    lattice->fYDivs = buffer.skipT<int32_t>(lattice->fYCount);
    int flagCount = buffer.readInt();
    lattice->fRectTypes = nullptr;
    lattice->fColors = nullptr;
    if (flagCount) {
        lattice->fRectTypes = buffer.skipT<SkCanvas::Lattice::RectType>(flagCount);
        lattice->fColors = buffer.skipT<SkColor>(flagCount);
    }
    lattice->fBounds = buffer.skipT<SkIRect>();
    return buffer.isValid();
}

size_t SkCanvasPriv::WriteLattice(void* buffer, const SkCanvas::Lattice& lattice) {
    int flagCount = lattice.fRectTypes ? (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;

    const size_t size = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * sizeof(int32_t) +
                        SkAlign4(flagCount * sizeof(SkCanvas::Lattice::RectType)) +
                        SkAlign4(flagCount * sizeof(SkColor)) +
                        sizeof(SkIRect);

    if (buffer) {
        SkWriter32 writer(buffer, size);
        writer.write32(lattice.fXCount);
        writer.write(lattice.fXDivs, lattice.fXCount * sizeof(uint32_t));
        writer.write32(lattice.fYCount);
        writer.write(lattice.fYDivs, lattice.fYCount * sizeof(uint32_t));
        writer.write32(flagCount);
        writer.writePad(lattice.fRectTypes, flagCount * sizeof(uint8_t));
        writer.write(lattice.fColors, flagCount * sizeof(SkColor));
        SkASSERT(lattice.fBounds);
        writer.write(lattice.fBounds, sizeof(SkIRect));
        SkASSERT(writer.bytesWritten() == size);
    }
    return size;
}

void SkCanvasPriv::WriteLattice(SkWriteBuffer& buffer, const SkCanvas::Lattice&&nbsp;lattice) {
    const size_t size = WriteLattice(nullptr, lattice);
    SkAutoSMalloc<1024> storage(size);
    WriteLattice(storage.get(), lattice);
    buffer.writePad32(storage.get(), size);
}

void SkCanvasPriv::GetDstClipAndMatrixCounts(const SkCanvas::ImageSetEntry set[], int count,
                                             int* totalDstClipCount, int* totalMatrixCount) {
    int dstClipCount = 0;
    int maxMatrixIndex = -1;
    for (int i = 0; i < count; ++i) {
        dstClipCount += 4 * set[i].fHasClip;
        if (set[i].fMatrixIndex > maxMatrixIndex) {
            maxMatrixIndex = set[i].fMatrixIndex;
        }
    }

    *totalDstClipCount = dstClipCount;
    *totalMatrixCount = maxMatrixIndex + 1;
}

// Attempts to convert an image filter to its equivalent color filter, which if possible, modifies
// the paint to compose the image filter's color filter into the paint's color filter slot. Returns
// true if the paint has been modified. Requires the paint to have an image filter.
bool SkCanvasPriv::ImageToColorFilter(SkPaint* paint) {
    SkASSERT(SkToBool(paint) && paint->getImageFilter());

    // An image filter logically runs after any mask filter and the src-over blending against the
    // layer's transparent black initial content. Moving the image filter (as a color filter) into
    // the color filter slot causes it to run before the mask filter or blending.
    //
    // Src-over blending against transparent black is a no-op, so skipping the layer and drawing the
    // output of the color filter-image filter with the original blender is valid.
    //
    // If there's also a mask filter on the paint, it will operate on an alpha-only layer that's
    // then shaded with the paint's effects. Moving the CF-IF into the paint's color filter slot
    // will mean that the CF-IF operates on the output of the original CF *before* it's combined
    // with the coverage value. Under normal circumstances the CF-IF evaluates the color after
    // coverage has been multiplied into the alpha channel.
    //
    // Some color filters may behave the same, e.g. cf(color)*coverage == cf(color*coverage), but
    // that's hard to detect so we disable the optimization when both image filters and mask filters
    // are present.
    if (paint->getMaskFilter()) {
        return false;
    }

    SkColorFilter* imgCFPtr;
    if (!paint->getImageFilter()->asAColorFilter(&imgCFPtr)) {
        return false;
    }
    sk_sp<SkColorFilter> imgCF(imgCFPtr);

    SkColorFilter* paintCF = paint->getColorFilter();
    if (paintCF) {
        // The paint has both a colorfilter(paintCF) and an imagefilter-that-is-a-colorfilter(imgCF)
        // and we need to combine them into a single colorfilter.
        imgCF = imgCF->makeComposed(sk_ref_sp(paintCF));
    }

    paint->setColorFilter(std::move(imgCF));
    paint->setImageFilter(nullptr);
    return true;
}

AutoLayerForImageFilter::AutoLayerForImageFilter(SkCanvas* canvas,
                                                 const SkPaint& paint,
                                                 const SkRect* rawBounds,
                                                 bool skipMaskFilterLayer)
            : fPaint(paint)
            , fCanvas(canvas)
            , fTempLayersForFilters(0) {
    SkDEBUGCODE(fSaveCount = canvas->getSaveCount();)

    // Depending on the original paint, this will add 0, 1, or 2 layers that apply the
    // filter effects to a temporary layer that rasterized the remaining effects. Image filters
    // are applied to the result of any mask filter, so its layer is added first in the stack.
    //
    // If present on the original paint, the image filter layer's restore paint steals the blender
    // and the image filter so that the draw's paint will never have an image filter.
    if (fPaint.getImageFilter() && !SkCanvasPriv::ImageToColorFilter(&fPaint)) {
        this->addImageFilterLayer(rawBounds);
    }

    // If present on the original paint, the mask filter layer's restore paint steals all shading
    // effects and the draw's paint shading is updated to draw a solid opaque color (thus encoding
    // coverage into the alpha channel). The draw's paint preserves all geometric effects that have
    // to be applied before the mask filter. The layer's restore paint adds an image filter
    // representing the mask filter.
    if (fPaint.getMaskFilter() && !skipMaskFilterLayer) {
        this->addMaskFilterLayer(rawBounds);
    }

   // When the original paint has both an image filter and a mask filter, this will create two
   // internal layers and perform two restores when finished. This actually creates one fewer
   // offscreen passes compared to directly composing the mask filter's output with an
   // SkImageFilters::Shader node and passing that into the rest of the image filter.
}

AutoLayerForImageFilter::~AutoLayerForImageFilter() {
    for (int i = 0; i < fTempLayersForFilters; ++i) {
        fCanvas->fSaveCount -= 1;
        fCanvas->internalRestore();
    }
    // Negative save count occurs when this layer was moved.
    SkASSERT(fSaveCount < 0 || fCanvas->getSaveCount() == fSaveCount);
}

AutoLayerForImageFilter::AutoLayerForImageFilter(AutoLayerForImageFilter&& other) {
    *this = std::move(other);
}

AutoLayerForImageFilter& AutoLayerForImageFilter::operator=(AutoLayerForImageFilter&& other) {
    fPaint = std::move(other.fPaint);
    fCanvas = other.fCanvas;
    fTempLayersForFilters = other.fTempLayersForFilters;
    SkDEBUGCODE(fSaveCount = other.fSaveCount;)

    other.fTempLayersForFilters = 0;
    SkDEBUGCODE(other.fSaveCount = -1;)

    return *this;
}

void AutoLayerForImageFilter::addImageFilterLayer(const SkRect* drawBounds) {
    // Shouldn't be adding a layer if there was no image filter to begin with.
    SkASSERT(fPaint.getImageFilter());

    // The restore paint for an image filter layer simply takes the image filter and blending off
    // the original paint. The blending is applied post image filter because otherwise it'd be
    // applied with the new layer's transparent dst and not be very interesting.
    SkPaint restorePaint;
    restorePaint.setImageFilter(fPaint.refImageFilter());
    restorePaint.setBlender(fPaint.refBlender());

    // Remove the restorePaint fields from our "working" paint, leaving all other shading and
    // geometry effects to be rendered into the layer. If there happens to be a mask filter, this
    // paint will still trigger a second layer for that filter.
    fPaint.setImageFilter(nullptr);
    fPaint.setBlendMode(SkBlendMode::kSrcOver);

    this->addLayer(restorePaint, drawBounds, /*coverageOnly=*/false);
}

void AutoLayerForImageFilter::addMaskFilterLayer(const SkRect* drawBounds) {
    // Shouldn't be adding a layer if there was no mask filter to begin with.
    SkASSERT(fPaint.getMaskFilter());

    // Image filters are evaluated after mask filters so any filter should have been converted to
    // a layer and removed from fPaint already.
    SkASSERT(!fPaint.getImageFilter());

    // TODO: Eventually all SkMaskFilters will implement this method so this can switch to an assert
    sk_sp<SkImageFilter> maskFilterAsImageFilter =
            as_MFB(fPaint.getMaskFilter())->asImageFilter(fCanvas->getTotalMatrix());
    if (!maskFilterAsImageFilter) {
        // This is a legacy mask filter that can be handled by raster and Ganesh directly, but will
        // be ignored by Graphite. Return now, leaving the paint with the mask filter so that the
        // underlying SkDevice can handle it if it will.
        return;
    }

    // The restore paint for the coverage layer takes over all shading effects that had been on the
    // original paint, which will be applied to the alpha-only output image from the mask filter
    // converted to an image filter.
    SkPaint restorePaint;
    restorePaint.setColor4f(fPaint.getColor4f());
    restorePaint.setShader(fPaint.refShader());
    restorePaint.setColorFilter(fPaint.refColorFilter());
    restorePaint.setBlender(fPaint.refBlender());
    restorePaint.setDither(fPaint.isDither());
    restorePaint.setImageFilter(maskFilterAsImageFilter);

    // Remove all shading effects from the "working" paint so that the layer's alpha channel
    // will correspond to the coverage. This leaves the original style and AA settings that
    // contribute to coverage (including any path effect).
    fPaint.setColor4f(SkColors::kWhite);
    fPaint.setShader(nullptr);
    fPaint.setColorFilter(nullptr);
    fPaint.setMaskFilter(nullptr);
    fPaint.setDither(false);
    fPaint.setBlendMode(SkBlendMode::kSrcOver);

    this->addLayer(restorePaint, drawBounds, /*coverageOnly=*/true);
}

void AutoLayerForImageFilter::addLayer(const SkPaint& restorePaint,
                                       const SkRect* drawBounds,
                                       bool coverageOnly) {
    SkRect storage;
    const SkRect* contentBounds = nullptr;
    if (drawBounds && fPaint.canComputeFastBounds()) {
        // The content bounds will include all paint outsets except for those that have been
        // extracted into 'restorePaint' or a previously added layer.
        contentBounds = &fPaint.computeFastBounds(*drawBounds, &storage);
    }

    fCanvas->fSaveCount += 1;
    fCanvas->internalSaveLayer(SkCanvas::SaveLayerRec(contentBounds, &restorePaint),
                               SkCanvas::kFullLayer_SaveLayerStrategy,
                               coverageOnly);
    fTempLayersForFilters += 1;
}

Messung V0.5
C=90 H=93 G=91

¤ Dauer der Verarbeitung: 0.5 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.