/*
 * Copyright 2018 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkGlyphRunPainter_DEFINED
#define SkGlyphRunPainter_DEFINED

#include "SkDistanceFieldGen.h"
#include "SkGlyphRun.h"
#include "SkScalerContext.h"
#include "SkSurfaceProps.h"
#include "SkTextBlobPriv.h"

#if SK_SUPPORT_GPU
#include "text/GrTextContext.h"
class GrColorSpaceInfo;
class GrRenderTargetContext;
#endif

class SkGlyphRunPainterInterface;

class SkStrikeCommon {
public:
    static SkVector PixelRounding(bool isSubpixel, SkAxisAlignment axisAlignment);

    // This assumes that position has the appropriate rounding term applied.
    static SkIPoint SubpixelLookup(SkAxisAlignment axisAlignment, SkPoint position);

    // An atlas consists of plots, and plots hold glyphs. The minimum a plot can be is 256x256.
    // This means that the maximum size a glyph can be is 256x256.
    static constexpr uint16_t kSkSideTooBigForAtlas = 256;

    static bool GlyphTooBigForAtlas(const SkGlyph& glyph);
};

class SkGlyphRunListPainter {
public:
    // Constructor for SkBitmpapDevice.
    SkGlyphRunListPainter(const SkSurfaceProps& props,
                          SkColorType colorType,
                          SkColorSpace* cs,
                          SkStrikeCacheInterface* strikeCache);

#if SK_SUPPORT_GPU
    // The following two ctors are used exclusively by the GPU, and will always use the global
    // strike cache.
    SkGlyphRunListPainter(const SkSurfaceProps&, const GrColorSpaceInfo&);
    explicit SkGlyphRunListPainter(const GrRenderTargetContext& renderTargetContext);
#endif  // SK_SUPPORT_GPU

    class BitmapDevicePainter {
    public:
        virtual ~BitmapDevicePainter() = default;

        virtual void paintPaths(SkSpan<const SkPathPos> pathsAndPositions,
                                SkScalar scale,
                                const SkPaint& paint) const = 0;

        virtual void paintMasks(SkSpan<const SkMask> masks, const SkPaint& paint) const = 0;
    };

    void drawForBitmapDevice(
            const SkGlyphRunList& glyphRunList, const SkMatrix& deviceMatrix,
            const BitmapDevicePainter* bitmapDevice);

#if SK_SUPPORT_GPU
    // A nullptr for process means that the calls to the cache will be performed, but none of the
    // callbacks will be called.
    void processGlyphRunList(const SkGlyphRunList& glyphRunList,
                             const SkMatrix& viewMatrix,
                             const SkSurfaceProps& props,
                             bool contextSupportsDistanceFieldText,
                             const GrTextContext::Options& options,
                             SkGlyphRunPainterInterface* process);
#endif  // SK_SUPPORT_GPU

    // TODO: Make this the canonical check for Skia.
    static bool ShouldDrawAsPath(const SkPaint& paint, const SkFont& font, const SkMatrix& matrix);

private:
    SkGlyphRunListPainter(const SkSurfaceProps& props, SkColorType colorType,
                          SkScalerContextFlags flags, SkStrikeCacheInterface* strikeCache);

    struct ScopedBuffers {
        ScopedBuffers(SkGlyphRunListPainter* painter, int size);
        ~ScopedBuffers();
        SkGlyphRunListPainter* fPainter;
    };

    ScopedBuffers SK_WARN_UNUSED_RESULT ensureBuffers(const SkGlyphRunList& glyphRunList);

    // TODO: Remove once I can hoist ensureBuffers above the list for loop in all cases.
    ScopedBuffers SK_WARN_UNUSED_RESULT ensureBuffers(const SkGlyphRun& glyphRun);

    /**
     *  @param fARGBPositions in source space
     *  @param fARGBGlyphsIDs the glyphs to process
     *  @param fGlyphPos used as scratch space
     *  @param maxSourceGlyphDimension the longest dimension of any glyph as if all fARGBGlyphsIDs
     *                                 were drawn in source space (as if viewMatrix were identity)
     */
    void processARGBFallback(SkScalar maxSourceGlyphDimension,
                             const SkPaint& runPaint,
                             const SkFont& runFont,
                             const SkMatrix& viewMatrix,
                             SkGlyphRunPainterInterface* process);

    // The props as on the actual device.
    const SkSurfaceProps fDeviceProps;
    // The props for when the bitmap device can't draw LCD text.
    const SkSurfaceProps fBitmapFallbackProps;
    const SkColorType fColorType;
    const SkScalerContextFlags fScalerContextFlags;

    SkStrikeCacheInterface* const fStrikeCache;

    int fMaxRunSize{0};
    SkAutoTMalloc<SkPoint> fPositions;
    SkAutoTMalloc<SkGlyphPos> fGlyphPos;

    std::vector<SkGlyphPos> fPaths;

    // Vectors for tracking ARGB fallback information.
    std::vector<SkGlyphID> fARGBGlyphsIDs;
    std::vector<SkPoint>   fARGBPositions;
};

// SkGlyphRunPainterInterface are all the ways that Ganesh generates glyphs. The first
// distinction is between Device and Source.
// * Device - the data in the cache is scaled to the device. There is no transformation from the
//   cache to the screen.
// * Source - the data in the cache needs to be scaled from the cache to source space using the
//   factor cacheToSourceScale. When drawn the system must combine cacheToSourceScale and the
//   deviceView matrix to transform the cache data onto the screen. This allows zooming and
//   simple animation to reuse the same glyph data by just changing the transform.
//
// In addition to transformation type above, Masks, Paths, SDFT, and Fallback (or really the
// rendering method of last resort) are the different
// formats of data used from the cache.
class SkGlyphRunPainterInterface {
public:
    virtual ~SkGlyphRunPainterInterface() = default;

    virtual void startRun(const SkGlyphRun& glyphRun, bool useSDFT) = 0;

    virtual void processDeviceMasks(SkSpan<const SkGlyphPos> masks,
                                    SkStrikeInterface* strike) = 0;

    virtual void processSourcePaths(SkSpan<const SkGlyphPos> paths,
                                    SkStrikeInterface* strike, SkScalar cacheToSourceScale) = 0;

    virtual void processDevicePaths(SkSpan<const SkGlyphPos> paths) = 0;

    virtual void processSourceSDFT(SkSpan<const SkGlyphPos> masks,
                                   SkStrikeInterface* strike,
                                   const SkFont& runFont,
                                   SkScalar cacheToSourceScale,
                                   SkScalar minScale,
                                   SkScalar maxScale,
                                   bool hasWCoord) = 0;

    virtual void processSourceFallback(SkSpan<const SkGlyphPos> masks,
                                       SkStrikeInterface* strike,
                                       SkScalar cacheToSourceScale,
                                       bool hasW) = 0;

    virtual void processDeviceFallback(SkSpan<const SkGlyphPos> masks,
                                       SkStrikeInterface* strike) = 0;

};

#endif  // SkGlyphRunPainter_DEFINED