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

#ifndef skgpu_graphite_geom_SubRunData_DEFINED
#define skgpu_graphite_geom_SubRunData_DEFINED

#include "include/core/SkM44.h"
#include "src/gpu/graphite/geom/Rect.h"
#include "src/text/gpu/SubRunContainer.h"

namespace sktext::gpu { class AtlasSubRun; }

namespace skgpu::graphite {

class Recorder;

/**
 * SubRunData represents an AtlasSubRun subspan for which per-pixel coverage data comes from a
 * persistent glyph atlas texture.
 *
 * The bounds() represent the bounds of the entire AtlasSubRun and does not directly map to the
 * local coordinates of this particular subspan. Rather, the dimensions and offset coordinates of a
 * subspan are defined in a coordinate space that is partially transformed by a decomposition of
 * the local-to-device matrix computed by the AtlasSubRun per instance. The transform of the draw is
 * the rest of the decomposed transform (often only a translation) that maps this intermediate space
 * to the device-space coordinates of the draw.
 *
 * The local coordinates used in shading are derived by transforming the final device coordinates
 * using the inverse of the local-to-device matrix.
 */
class SubRunData {
public:
    SubRunData() = delete;
    SubRunData(const SubRunData& subRun) = default;
    SubRunData(SubRunData&&) = delete;

    SubRunData(const sktext::gpu::AtlasSubRun* subRun,
               sk_sp<SkRefCnt> supportDataKeepAlive,
               Rect deviceBounds,
               const SkM44& deviceToLocal,
               int startGlyphIndex,
               int glyphCount,
               Recorder* recorder,
               sktext::gpu::RendererData rendererData)
        : fSubRun(subRun)
        , fSupportDataKeepAlive(std::move(supportDataKeepAlive))
        , fBounds(deviceBounds)
        , fDeviceToLocal(deviceToLocal)
        , fStartGlyphIndex(startGlyphIndex)
        , fGlyphCount(glyphCount)
        , fRecorder(recorder)
        , fRendererData(rendererData) {}

    ~SubRunData() = default;

    // NOTE: None of the geometry types benefit from move semantics, so we don't bother
    // defining a move assignment operator for SubRunData.
    SubRunData& operator=(SubRunData&&) = delete;
    SubRunData& operator=(const SubRunData& that) = default;

    // The bounding box of the originating AtlasSubRun.
    Rect bounds() const { return fBounds; }

    // The inverse local-to-device matrix.
    const SkM44& deviceToLocal() const { return fDeviceToLocal; }

    // Access the individual elements of the subrun data.
    const sktext::gpu::AtlasSubRun* subRun() const { return fSubRun; }
    int startGlyphIndex() const { return fStartGlyphIndex; }
    int glyphCount() const { return fGlyphCount; }
    Recorder* recorder() const { return fRecorder; }
    const sktext::gpu::RendererData& rendererData() const { return fRendererData; }

private:
    const sktext::gpu::AtlasSubRun* fSubRun;
    // Keep the TextBlob or Slug alive until we're done with the Geometry.
    sk_sp<SkRefCnt> fSupportDataKeepAlive;

    Rect fBounds;  // bounds of the data stored in the SubRun
    SkM44 fDeviceToLocal;
    int fStartGlyphIndex;
    int fGlyphCount;
    Recorder* fRecorder; // this SubRun can only be associated with this Recorder's atlas
    sktext::gpu::RendererData fRendererData;
};

} // namespace skgpu::graphite

#endif // skgpu_graphite_geom_SubRunData_DEFINED
