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

#ifndef GrCCPathParser_DEFINED
#define GrCCPathParser_DEFINED

#include "GrMesh.h"
#include "GrNonAtomicRef.h"
#include "GrTessellator.h"
#include "SkRect.h"
#include "SkRefCnt.h"
#include "ccpr/GrCCCoverageProcessor.h"
#include "ccpr/GrCCGeometry.h"
#include "ops/GrDrawOp.h"

class GrOnFlushResourceProvider;
class SkMatrix;
class SkPath;

/**
 * This class parses SkPaths into CCPR primitives in GPU buffers, then issues calls to draw their
 * coverage counts.
 */
class GrCCPathParser : public GrNonAtomicRef<GrCCPathParser> {
public:
    // Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified
    // as an int because these values get used directly as indices into arrays.)
    enum class ScissorMode : int { kNonScissored = 0, kScissored = 1 };
    static constexpr int kNumScissorModes = 2;

    GrCCPathParser(int maxTotalPaths, int maxPathPoints, int numSkPoints, int numSkVerbs);

    ~GrCCPathParser() {
        // Enforce the contract that the client always calls saveParsedPath or discardParsedPath.
        SkASSERT(!fParsingPath);
    }

    using CoverageCountBatchID = int;

    // Parses an SkPath into a temporary staging area. The path will not be included in the current
    // batch until there is a matching call to saveParsedPath. The user must complement this with a
    // following call to either saveParsedPath or discardParsedPath.
    //
    // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space.
    //                                                                 | 1  1 |
    void parsePath(const SkMatrix&, const SkPath&, SkRect* devBounds, SkRect* devBounds45);

    // Parses a device-space SkPath into a temporary staging area. The path will not be included in
    // the current batch until there is a matching call to saveParsedPath. The user must complement
    // this with a following call to either saveParsedPath or discardParsedPath.
    void parseDeviceSpacePath(const SkPath&);

    // Commits the currently-parsed path from staging to the current batch, and specifies whether
    // the mask should be rendered with a scissor in effect. Accepts an optional post-device-space
    // translate for placement in an atlas.
    void saveParsedPath(ScissorMode, const SkIRect& clippedDevIBounds, int16_t atlasOffsetX,
                        int16_t atlasOffsetY);
    void discardParsedPath();

    // Compiles the outstanding saved paths into a batch, and returns an ID that can be used to draw
    // their coverage counts in the future.
    CoverageCountBatchID closeCurrentBatch();

    // Builds internal GPU buffers and prepares for calls to drawCoverageCount. Caller must close
    // the current batch before calling this method, and cannot parse new paths afer.
    bool finalize(GrOnFlushResourceProvider*);

    // Called after finalize. Draws the given batch of parsed paths.
    void drawCoverageCount(GrOpFlushState*, CoverageCountBatchID, const SkIRect& drawBounds) const;

private:
    using PrimitiveTallies = GrCCGeometry::PrimitiveTallies;

    // Every kBeginPath verb has a corresponding PathInfo entry.
    class PathInfo {
    public:
        PathInfo(ScissorMode scissorMode, int16_t offsetX, int16_t offsetY)
                : fScissorMode(scissorMode), fAtlasOffsetX(offsetX), fAtlasOffsetY(offsetY) {}

        ScissorMode scissorMode() const { return fScissorMode; }
        int16_t atlasOffsetX() const { return fAtlasOffsetX; }
        int16_t atlasOffsetY() const { return fAtlasOffsetY; }

        // An empty tessellation fan is also valid; we use negative count to denote not tessellated.
        bool hasFanTessellation() const { return fFanTessellationCount >= 0; }
        int fanTessellationCount() const {
            SkASSERT(this->hasFanTessellation());
            return fFanTessellationCount;
        }
        const GrTessellator::WindingVertex* fanTessellation() const {
            SkASSERT(this->hasFanTessellation());
            return fFanTessellation.get();
        }

        void adoptFanTessellation(const GrTessellator::WindingVertex* vertices, int count) {
            SkASSERT(count >= 0);
            fFanTessellation.reset(vertices);
            fFanTessellationCount = count;
        }

    private:
        ScissorMode fScissorMode;
        int16_t fAtlasOffsetX, fAtlasOffsetY;
        int fFanTessellationCount = -1;
        std::unique_ptr<const GrTessellator::WindingVertex[]> fFanTessellation;
    };

    // Defines a batch of CCPR primitives. Start indices are deduced by looking at the previous
    // CoverageCountBatch in the list.
    struct CoverageCountBatch {
        PrimitiveTallies fEndNonScissorIndices;
        int fEndScissorSubBatchIdx;
        PrimitiveTallies fTotalPrimitiveCounts;
    };

    // Defines a sub-batch from CoverageCountBatch that will be drawn with the given scissor rect.
    // Start indices are deduced by looking at the previous ScissorSubBatch in the list.
    struct ScissorSubBatch {
        PrimitiveTallies fEndPrimitiveIndices;
        SkIRect fScissor;
    };

    void parsePath(const SkPath&, const SkPoint* deviceSpacePts);
    void endContourIfNeeded(bool insideContour);

    void drawPrimitives(GrOpFlushState*, const GrPipeline&, CoverageCountBatchID,
                        GrCCCoverageProcessor::PrimitiveType, int PrimitiveTallies::*instanceType,
                        const SkIRect& drawBounds) const;

    // Staging area for the path being parsed.
    SkDEBUGCODE(int fParsingPath = false);
    const SkAutoSTArray<32, SkPoint> fLocalDevPtsBuffer;
    int fCurrPathPointsIdx;
    int fCurrPathVerbsIdx;
    PrimitiveTallies fCurrPathPrimitiveCounts;

    GrCCGeometry fGeometry;
    SkSTArray<32, PathInfo, true> fPathsInfo;
    SkSTArray<32, CoverageCountBatch, true> fCoverageCountBatches;
    SkSTArray<32, ScissorSubBatch, true> fScissorSubBatches;
    PrimitiveTallies fTotalPrimitiveCounts[kNumScissorModes];
    int fMaxMeshesPerDraw = 0;

    sk_sp<GrBuffer> fInstanceBuffer;
    PrimitiveTallies fBaseInstances[kNumScissorModes];
    mutable SkSTArray<32, GrMesh> fMeshesScratchBuffer;
    mutable SkSTArray<32, GrPipeline::DynamicState> fDynamicStatesScratchBuffer;
};

#endif
