1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "modules/sksg/include/SkSGMaskEffect.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 11cb93a386Sopenharmony_ci#include "include/effects/SkLumaColorFilter.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_cinamespace sksg { 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_cistatic bool is_inverted(sksg::MaskEffect::Mode mode) { 16cb93a386Sopenharmony_ci return static_cast<uint32_t>(mode) & 1; 17cb93a386Sopenharmony_ci}; 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cistatic bool is_luma(sksg::MaskEffect::Mode mode) { 20cb93a386Sopenharmony_ci return static_cast<uint32_t>(mode) & 2; 21cb93a386Sopenharmony_ci} 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciMaskEffect::MaskEffect(sk_sp<RenderNode> child, sk_sp<RenderNode> mask, Mode mode) 24cb93a386Sopenharmony_ci : INHERITED(std::move(child)) 25cb93a386Sopenharmony_ci , fMaskNode(std::move(mask)) 26cb93a386Sopenharmony_ci , fMaskMode(mode) { 27cb93a386Sopenharmony_ci this->observeInval(fMaskNode); 28cb93a386Sopenharmony_ci} 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ciMaskEffect::~MaskEffect() { 31cb93a386Sopenharmony_ci this->unobserveInval(fMaskNode); 32cb93a386Sopenharmony_ci} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_civoid MaskEffect::onRender(SkCanvas* canvas, const RenderContext* ctx) const { 35cb93a386Sopenharmony_ci SkAutoCanvasRestore acr(canvas, false); 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci // The mask mode covers two independent bits. 38cb93a386Sopenharmony_ci // 39cb93a386Sopenharmony_ci // - mask source controls how the mask coverage is generated: 40cb93a386Sopenharmony_ci // * alpha => coverage = mask_alpha 41cb93a386Sopenharmony_ci // * luma => coverage = luma(mask_rgb) 42cb93a386Sopenharmony_ci // 43cb93a386Sopenharmony_ci // - mask type controls how the mask coverage is interpreted: 44cb93a386Sopenharmony_ci // * normal => coverage' = coverage 45cb93a386Sopenharmony_ci // * inverted => coverage' = 1 - coverage 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci { 48cb93a386Sopenharmony_ci // Outer layer: mask coverage stored in the alpha channel. 49cb93a386Sopenharmony_ci SkPaint mask_layer_paint; 50cb93a386Sopenharmony_ci if (ctx) { 51cb93a386Sopenharmony_ci // Apply all optional context overrides upfront. 52cb93a386Sopenharmony_ci ctx->modulatePaint(canvas->getTotalMatrix(), &mask_layer_paint); 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci RenderContext mask_render_context; 56cb93a386Sopenharmony_ci if (is_luma(fMaskMode)) { 57cb93a386Sopenharmony_ci mask_render_context.fColorFilter = SkLumaColorFilter::Make(); 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci // TODO: could be an A8 layer? 61cb93a386Sopenharmony_ci canvas->saveLayer(this->bounds(), &mask_layer_paint); 62cb93a386Sopenharmony_ci fMaskNode->render(canvas, &mask_render_context); 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci { 65cb93a386Sopenharmony_ci // Inner layer: masked content. 66cb93a386Sopenharmony_ci SkPaint content_layer_paint; 67cb93a386Sopenharmony_ci content_layer_paint.setBlendMode(is_inverted(fMaskMode) ? SkBlendMode::kSrcOut 68cb93a386Sopenharmony_ci : SkBlendMode::kSrcIn); 69cb93a386Sopenharmony_ci canvas->saveLayer(this->bounds(), &content_layer_paint); 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci this->INHERITED::onRender(canvas, nullptr); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci} 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ciconst RenderNode* MaskEffect::onNodeAt(const SkPoint& p) const { 77cb93a386Sopenharmony_ci const auto mask_hit = (SkToBool(fMaskNode->nodeAt(p)) == !is_inverted(fMaskMode)); 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci if (!mask_hit) { 80cb93a386Sopenharmony_ci return nullptr; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci return this->INHERITED::onNodeAt(p); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ciSkRect MaskEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) { 87cb93a386Sopenharmony_ci SkASSERT(this->hasInval()); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci const auto maskBounds = fMaskNode->revalidate(ic, ctm); 90cb93a386Sopenharmony_ci auto childBounds = this->INHERITED::onRevalidate(ic, ctm); 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci return (is_inverted(fMaskMode) || childBounds.intersect(maskBounds)) 93cb93a386Sopenharmony_ci ? childBounds 94cb93a386Sopenharmony_ci : SkRect::MakeEmpty(); 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci} // namespace sksg 98