| /* |
| * Copyright 2025 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef ZoomInSlide_DEFINED |
| #define ZoomInSlide_DEFINED |
| |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkColor.h" |
| #include "include/core/SkImage.h" |
| #include "include/core/SkImageInfo.h" |
| #include "include/core/SkPaint.h" |
| #include "include/core/SkPath.h" |
| #include "include/core/SkPoint.h" |
| #include "include/core/SkSurface.h" |
| #include "tools/viewer/ClickHandlerSlide.h" |
| #include "tools/viewer/Slide.h" |
| |
| class SkString; |
| |
| /** |
| * A utility slide for visualizing small paths scaled up to show pixel rasterization. |
| * |
| * This slide renders a scene into a small offscreen surface (representing the "pixels"), |
| * and then draws that surface scaled up onto the screen. This allows inspecting |
| * anti-aliasing and rasterization details. |
| * |
| * It provides a grid overlay and handles coordinate mapping for mouse interactions (only |
| * when control is pressed). |
| */ |
| class ZoomInSlide : public ClickHandlerSlide { |
| public: |
| ZoomInSlide(size_t scale, size_t width, size_t height, SkString name) |
| : fScale(scale), fWidth(width), fHeight(height) { |
| fName = name; |
| } |
| |
| protected: |
| const size_t fScale; |
| const size_t fWidth; |
| const size_t fHeight; |
| |
| /** |
| * Helper to rasterize a path into a small surface and draw it scaled up. |
| * This visualizes how the path is rasterized into pixels. |
| * |
| * @param canvas The canvas to draw onto (already scaled by fScale). |
| * @param path The path to rasterize. |
| * @param pathPaint The paint to use for rasterization. |
| */ |
| void drawScaledPath(SkCanvas* canvas, const SkPath& path, const SkPaint& pathPaint) { |
| auto ii = SkImageInfo::MakeN32Premul(fWidth, fHeight); |
| auto surface = SkSurfaces::Raster(ii); |
| SkASSERT_RELEASE(surface); |
| |
| surface->getCanvas()->clear(SK_ColorTRANSPARENT); |
| surface->getCanvas()->drawPath(path, pathPaint); |
| auto pathImg = surface->makeImageSnapshot(); |
| |
| canvas->drawImage(pathImg, 0, 0); |
| } |
| |
| class ScaledClick : public ClickHandlerSlide::Click { |
| public: |
| ScaledClick(size_t scale) : fScale(scale) {} |
| |
| // Returns the click coordinates in the small (unscaled) space. |
| SkPoint currScaled() const { return {fCurr.fX / fScale, fCurr.fY / fScale}; } |
| |
| private: |
| const size_t fScale; |
| }; |
| |
| private: |
| void draw(SkCanvas* canvas) override { |
| canvas->scale(fScale, fScale); |
| canvas->clear(SK_ColorWHITE); |
| |
| this->drawUnderGrid(canvas); |
| this->drawGrid(canvas); |
| this->drawOverGrid(canvas); |
| } |
| |
| /** |
| * Draw content that should be subject to "pixel inspection". |
| */ |
| virtual void drawUnderGrid(SkCanvas* canvas) = 0; |
| |
| /** |
| * Draw overlay content (like vector paths or handles) on top of the grid. |
| * Coordinates are in the small (unscaled) space. |
| */ |
| virtual void drawOverGrid(SkCanvas* canvas) = 0; |
| |
| void drawGrid(SkCanvas* canvas) { |
| SkPaint gridPaint; |
| gridPaint.setColor(SK_ColorDKGRAY); |
| gridPaint.setStyle(SkPaint::Style::kStroke_Style); |
| // Stroke width 0 means "hairline" (1 pixel on device). |
| // Since the canvas is scaled, this will be a very thin line relative to the "big pixels". |
| gridPaint.setStrokeWidth(0); |
| |
| for (int y = 0; y <= (int)fHeight; ++y) { |
| canvas->drawLine(0, y, fWidth, y, gridPaint); |
| } |
| for (int x = 0; x <= (int)fWidth; ++x) { |
| canvas->drawLine(x, 0, x, fHeight, gridPaint); |
| } |
| } |
| |
| /** |
| * Convenient callback for handling clicks in either the zoomed-out or zoomed-in space |
| */ |
| virtual void handleClick(const ScaledClick*) {} |
| |
| Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modifiers) override { |
| // Only activate when Control is held to avoid interfering with normal viewer panning. |
| if (modifiers != skui::ModifierKey::kControl) { |
| return nullptr; |
| } |
| return new ScaledClick(fScale); |
| } |
| |
| bool onClick(ClickHandlerSlide::Click* click) override { |
| auto myClick = static_cast<ScaledClick*>(click); |
| this->handleClick(myClick); |
| return true; |
| } |
| }; |
| |
| #endif |