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

Quelle  SkBlendMode.cpp   Sprache: C

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


#include "include/core/SkBlendMode.h"

#include "include/core/SkColor.h"
#include "include/core/SkPaint.h"
#include "include/private/SkColorData.h"
#include "src/base/SkVx.h"
#include "src/core/SkBlendModePriv.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkRasterPipelineOpContexts.h"
#include "src/core/SkRasterPipelineOpList.h"

#include <optional>

bool SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode, bool rgb_coverage) {
    // The most important things we do here are:
    //   1) never pre-scale with rgb coverage if the blend mode involves a source-alpha term;
    //   2) always pre-scale Plus.
    //
    // When we pre-scale with rgb coverage, we scale each of source r,g,b, with a distinct value,
    // and source alpha with one of those three values.  This process destructively updates the
    // source-alpha term, so we can't evaluate blend modes that need its original value.
    //
    // Plus always requires pre-scaling as a specific quirk of its implementation in
    // SkRasterPipeline.  This lets us put the clamp inside the blend mode itself rather
    // than as a separate stage that'd come after the lerp.
    //
    // This function is a finer-grained breakdown of SkBlendMode_SupportsCoverageAsAlpha().
    switch (mode) {
        case SkBlendMode::kDst:        // d              --> no sa term, ok!
        case SkBlendMode::kDstOver:    // d + s*inv(da)  --> no sa term, ok!
        case SkBlendMode::kPlus:       // clamp(s+d)     --> no sa term, ok!
            return true;

        case SkBlendMode::kDstOut:     // d * inv(sa)
        case SkBlendMode::kSrcATop:    // s*da + d*inv(sa)
        case SkBlendMode::kSrcOver:    // s + d*inv(sa)
        case SkBlendMode::kXor:        // s*inv(da) + d*inv(sa)
            return !rgb_coverage;

        defaultbreak;
    }
    return false;
}

// Users of this function may want to switch to the rgb-coverage aware version above.
bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) {
    return SkBlendMode_ShouldPreScaleCoverage(mode, false);
}

bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) {
    struct CoeffRec {
        SkBlendModeCoeff    fSrc;
        SkBlendModeCoeff    fDst;
    };

    static constexpr CoeffRec kCoeffs[] = {
        // For Porter-Duff blend functions, color = src * src coeff + dst * dst coeff
        // src coeff                  dst coeff                     blend func
        // ----------------------     -----------------------       ----------
        { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kZero }, // clear
        { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kZero }, // src
        { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kOne  }, // dst
        { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISA  }, // src-over
        { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kOne  }, // dst-over
        { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kZero }, // src-in
        { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSA   }, // dst-in
        { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kZero }, // src-out
        { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kISA  }, // dst-out
        { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kISA  }, // src-atop
        { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kSA   }, // dst-atop
        { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kISA  }, // xor

        { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kOne  }, // plus
        { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSC   }, // modulate
        { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISC  }, // screen
    };

    if (mode > SkBlendMode::kScreen) {
        return false;
    }
    if (src) {
        *src = kCoeffs[static_cast<int>(mode)].fSrc;
    }
    if (dst) {
        *dst = kCoeffs[static_cast<int>(mode)].fDst;
    }
    return true;
}

void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) {
    auto stage = SkRasterPipelineOp::srcover;
    switch (mode) {
        case SkBlendMode::kClear:    stage = SkRasterPipelineOp::clear; break;
        case SkBlendMode::kSrc:      return;  // This stage is a no-op.
        case SkBlendMode::kDst:      stage = SkRasterPipelineOp::move_dst_src; break;
        case SkBlendMode::kSrcOver:  stage = SkRasterPipelineOp::srcover; break;
        case SkBlendMode::kDstOver:  stage = SkRasterPipelineOp::dstover; break;
        case SkBlendMode::kSrcIn:    stage = SkRasterPipelineOp::srcin; break;
        case SkBlendMode::kDstIn:    stage = SkRasterPipelineOp::dstin; break;
        case SkBlendMode::kSrcOut:   stage = SkRasterPipelineOp::srcout; break;
        case SkBlendMode::kDstOut:   stage = SkRasterPipelineOp::dstout; break;
        case SkBlendMode::kSrcATop:  stage = SkRasterPipelineOp::srcatop; break;
        case SkBlendMode::kDstATop:  stage = SkRasterPipelineOp::dstatop; break;
        case SkBlendMode::kXor:      stage = SkRasterPipelineOp::xor_; break;
        case SkBlendMode::kPlus:     stage = SkRasterPipelineOp::plus_; break;
        case SkBlendMode::kModulate: stage = SkRasterPipelineOp::modulate; break;

        case SkBlendMode::kScreen:     stage = SkRasterPipelineOp::screen; break;
        case SkBlendMode::kOverlay:    stage = SkRasterPipelineOp::overlay; break;
        case SkBlendMode::kDarken:     stage = SkRasterPipelineOp::darken; break;
        case SkBlendMode::kLighten:    stage = SkRasterPipelineOp::lighten; break;
        case SkBlendMode::kColorDodge: stage = SkRasterPipelineOp::colordodge; break;
        case SkBlendMode::kColorBurn:  stage = SkRasterPipelineOp::colorburn; break;
        case SkBlendMode::kHardLight:  stage = SkRasterPipelineOp::hardlight; break;
        case SkBlendMode::kSoftLight:  stage = SkRasterPipelineOp::softlight; break;
        case SkBlendMode::kDifference: stage = SkRasterPipelineOp::difference; break;
        case SkBlendMode::kExclusion:  stage = SkRasterPipelineOp::exclusion; break;
        case SkBlendMode::kMultiply:   stage = SkRasterPipelineOp::multiply; break;

        case SkBlendMode::kHue:        stage = SkRasterPipelineOp::hue; break;
        case SkBlendMode::kSaturation: stage = SkRasterPipelineOp::saturation; break;
        case SkBlendMode::kColor:      stage = SkRasterPipelineOp::color; break;
        case SkBlendMode::kLuminosity: stage = SkRasterPipelineOp::luminosity; break;
    }
    p->append(stage);
}

SkPMColor4f SkBlendMode_Apply(SkBlendMode mode, const SkPMColor4f& src, const SkPMColor4f& dst) {
    // special-case simple/common modes...
    switch (mode) {
        case SkBlendMode::kClear:   return SK_PMColor4fTRANSPARENT;
        case SkBlendMode::kSrc:     return src;
        case SkBlendMode::kDst:     return dst;
        case SkBlendMode::kSrcOver: {
            SkPMColor4f r;
            (skvx::float4::Load(src.vec()) + skvx::float4::Load(dst.vec()) * (1-src.fA)).store(&r);
            return r;
        }
        default:
            break;
    }

    SkRasterPipeline_<256> p;
    SkPMColor4f            src_storage = src,
                           dst_storage = dst,
                           res_storage;
    SkRasterPipeline_MemoryCtx src_ctx = { &src_storage, 0 },
                               dst_ctx = { &dst_storage, 0 },
                               res_ctx = { &res_storage, 0 };

    p.append(SkRasterPipelineOp::load_f32, &dst_ctx);
    p.append(SkRasterPipelineOp::move_src_dst);
    p.append(SkRasterPipelineOp::load_f32, &src_ctx);
    SkBlendMode_AppendStages(mode, &p);
    p.append(SkRasterPipelineOp::store_f32, &res_ctx);
    p.run(0,0, 1,1);
    return res_storage;
}

const char* SkBlendMode_Name(SkBlendMode bm) {
    switch (bm) {
        case SkBlendMode::kClear:      return "Clear";
        case SkBlendMode::kSrc:        return "Src";
        case SkBlendMode::kDst:        return "Dst";
        case SkBlendMode::kSrcOver:    return "SrcOver";
        case SkBlendMode::kDstOver:    return "DstOver";
        case SkBlendMode::kSrcIn:      return "SrcIn";
        case SkBlendMode::kDstIn:      return "DstIn";
        case SkBlendMode::kSrcOut:     return "SrcOut";
        case SkBlendMode::kDstOut:     return "DstOut";
        case SkBlendMode::kSrcATop:    return "SrcATop";
        case SkBlendMode::kDstATop:    return "DstATop";
        case SkBlendMode::kXor:        return "Xor";
        case SkBlendMode::kPlus:       return "Plus";
        case SkBlendMode::kModulate:   return "Modulate";
        case SkBlendMode::kScreen:     return "Screen";

        case SkBlendMode::kOverlay:    return "Overlay";
        case SkBlendMode::kDarken:     return "Darken";
        case SkBlendMode::kLighten:    return "Lighten";
        case SkBlendMode::kColorDodge: return "ColorDodge";
        case SkBlendMode::kColorBurn:  return "ColorBurn";
        case SkBlendMode::kHardLight:  return "HardLight";
        case SkBlendMode::kSoftLight:  return "SoftLight";
        case SkBlendMode::kDifference: return "Difference";
        case SkBlendMode::kExclusion:  return "Exclusion";
        case SkBlendMode::kMultiply:   return "Multiply";

        case SkBlendMode::kHue:        return "Hue";
        case SkBlendMode::kSaturation: return "Saturation";
        case SkBlendMode::kColor:      return "Color";
        case SkBlendMode::kLuminosity: return "Luminosity";
    }
    SkUNREACHABLE;
}

static bool just_solid_color(const SkPaint& p) {
    return SK_AlphaOPAQUE == p.getAlpha() && !p.getColorFilter() && !p.getShader();
}

SkBlendFastPath CheckFastPath(const SkPaint& paint, bool dstIsOpaque) {
    const auto bm = paint.asBlendMode();
    if (!bm) {
        return SkBlendFastPath::kNormal;
    }
    switch (bm.value()) {
        case SkBlendMode::kSrcOver:
            return SkBlendFastPath::kSrcOver;
        case SkBlendMode::kSrc:
            if (just_solid_color(paint)) {
                return SkBlendFastPath::kSrcOver;
            }
            return SkBlendFastPath::kNormal;
        case SkBlendMode::kDst:
            return SkBlendFastPath::kSkipDrawing;
        case SkBlendMode::kDstOver:
            if (dstIsOpaque) {
                return SkBlendFastPath::kSkipDrawing;
            }
            return SkBlendFastPath::kNormal;
        case SkBlendMode::kSrcIn:
            if (dstIsOpaque && just_solid_color(paint)) {
                return SkBlendFastPath::kSrcOver;
            }
            return SkBlendFastPath::kNormal;
        case SkBlendMode::kDstIn:
            if (just_solid_color(paint)) {
                return SkBlendFastPath::kSkipDrawing;
            }
            return SkBlendFastPath::kNormal;
        default:
            return SkBlendFastPath::kNormal;
    }
}

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

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