| /* | |
| * Copyright 2026 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/SkBitmap.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPath.h" | |
| #include "include/core/SkSurface.h" | |
| #include "include/utils/SkCustomTypeface.h" | |
| #include "tests/CtsEnforcement.h" | |
| #include "tests/Test.h" | |
| #include <functional> | |
| #include <type_traits> | |
| #if defined(SK_GANESH) | |
| #include "include/gpu/ganesh/GrContextOptions.h" | |
| #include "include/gpu/ganesh/GrDirectContext.h" | |
| #include "include/gpu/ganesh/SkSurfaceGanesh.h" | |
| #endif | |
| #if defined(SK_GRAPHITE) | |
| #include "include/gpu/graphite/Context.h" | |
| #include "include/gpu/graphite/ContextOptions.h" | |
| #include "include/gpu/graphite/Recorder.h" | |
| #include "include/gpu/graphite/Surface.h" | |
| #include "src/gpu/graphite/ContextOptionsPriv.h" | |
| #endif | |
| template <typename T> | |
| static void disable_sdft_options(T* options) { | |
| options->fMinDistanceFieldFontSize = 384.f; | |
| options->fGlyphsAsPathsFontSize = 384.f; | |
| options->fSupportBilerpFromGlyphAtlas = true; | |
| if constexpr (std::is_same_v<T, GrContextOptions>) { | |
| options->fMaxTextureSizeOverride = 1024; | |
| } else { | |
| options->fOptionsPriv->fMaxTextureSizeOverride = 1024; | |
| } | |
| } | |
| static void test_direct_mask_limit(skiatest::Reporter* reporter, | |
| SkSurface* surface, | |
| const std::function<void()>& submit) { | |
| SkCanvas* canvas = surface->getCanvas(); | |
| canvas->clear(SK_ColorBLACK); | |
| SkCustomTypefaceBuilder builder; | |
| SkPath path = SkPath::Rect(SkRect::MakeLTRB(0.f, -1.f, 1.f, 0.f)); | |
| builder.setGlyph(1, 1.0f, path); | |
| SkFont font(builder.detach(), 253); | |
| font.setEdging(SkFont::Edging::kSubpixelAntiAlias); | |
| SkPaint paint; | |
| paint.setColor(SK_ColorWHITE); | |
| SkGlyphID glyph = 1; | |
| SkPoint position = {0, 0}; | |
| canvas->drawGlyphs({&glyph, 1}, {&position, 1}, {100, 300}, font, paint); | |
| submit(); | |
| SkBitmap bitmap; | |
| bitmap.allocN32Pixels(512, 512); | |
| REPORTER_ASSERT(reporter, surface->readPixels(bitmap, 0, 0)); | |
| bool hasWhitePixel = false; | |
| for (int y = 0; y < 512; ++y) { | |
| for (int x = 0; x < 512; ++x) { | |
| if (bitmap.getColor(x, y) != SK_ColorBLACK) { | |
| hasWhitePixel = true; | |
| break; | |
| } | |
| } | |
| if (hasWhitePixel) { | |
| break; | |
| } | |
| } | |
| REPORTER_ASSERT(reporter, hasWhitePixel, "Draw failed (all pixels are black)"); | |
| } | |
| #if defined(SK_GANESH) | |
| DEF_GANESH_TEST_FOR_CONTEXTS(DirectMaskLimitTest_Ganesh, | |
| skgpu::IsRenderingContext, | |
| reporter, | |
| ctxInfo, | |
| disable_sdft_options<GrContextOptions>, | |
| CtsEnforcement::kNever) { | |
| auto dContext = ctxInfo.directContext(); | |
| if (dContext->supportsProtectedContent()) { | |
| return; | |
| } | |
| auto surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, | |
| SkImageInfo::MakeN32Premul(512, 512)); | |
| if (!surface) { | |
| return; | |
| } | |
| test_direct_mask_limit(reporter, surface.get(), [&] { dContext->flushAndSubmit(); }); | |
| } | |
| #endif // SK_GANESH | |
| #if defined(SK_GRAPHITE) | |
| DEF_CONDITIONAL_GRAPHITE_TEST_FOR_CONTEXTS(DirectMaskLimitTest_Graphite, | |
| skgpu::IsRenderingContext, | |
| reporter, | |
| context, | |
| testContext, | |
| /* anonymous options */, | |
| disable_sdft_options<skgpu::graphite::ContextOptions>, | |
| /* condition= */ true, | |
| CtsEnforcement::kNever) { | |
| if (context->supportsProtectedContent()) { | |
| return; | |
| } | |
| auto recorder = context->makeRecorder(); | |
| if (!recorder) { | |
| return; | |
| } | |
| auto surface = SkSurfaces::RenderTarget(recorder.get(), | |
| SkImageInfo::MakeN32Premul(512, 512)); | |
| if (!surface) { | |
| return; | |
| } | |
| test_direct_mask_limit(reporter, surface.get(), [&] { | |
| auto recording = recorder->snap(); | |
| context->insertRecording({recording.get()}); | |
| context->submit(skgpu::graphite::SyncToCpu::kYes); | |
| }); | |
| } | |
| #endif // SK_GRAPHITE |