| /* |
| * Copyright 2020 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef SkMatrixProvider_DEFINED |
| #define SkMatrixProvider_DEFINED |
| |
| #include "include/core/SkM44.h" |
| #include "include/core/SkMatrix.h" |
| |
| /** |
| * All matrix providers report a flag: "localToDeviceHitsPixelCenters". This is confusing. |
| * It doesn't say anything about the actual matrix in the provider. Instead, it means: "is it safe |
| * to tweak sampling based on the contents of the matrix". In other words, does the device end of |
| * the local-to-device matrix actually map to pixels, AND are the local coordinates being fed to |
| * the shader produced by the inverse of that matrix? For a normal device, this is trivially true. |
| * The matrix may be updated via transforms, but when we draw (and the local coordinates come from |
| * rasterization of primitives against that device), we can know that the device coordinates will |
| * land on pixel centers. |
| * |
| * In a few places, the matrix provider is lying about how sampling "works". When we invoke a child |
| * from runtime effects, we give that child a matrix provider with an identity matrix. However -- |
| * the coordinates being passed to that child are not the result of device -> local transformed |
| * coordinates. Runtime effects can generate coordinates arbitrarily - even though the provider has |
| * an identity matrix, we can't assume it's safe to (for example) convert linear -> nearest. |
| * Clip shaders are similar - they overwrite the local-to-device matrix (to match what it was when |
| * the clip shader was inserted). The CTM continues to change before drawing, though. In that case, |
| * the two matrices are not inverses, so the local coordinates may not land on texel centers in |
| * the clip shader. |
| * |
| * In cases where we need to inhibit filtering optimizations, use SkOverrideDeviceMatrixProvider. |
| */ |
| class SkMatrixProvider { |
| public: |
| SkMatrixProvider(const SkMatrix& localToDevice) : SkMatrixProvider(localToDevice, true) {} |
| SkMatrixProvider(const SkM44& localToDevice) : SkMatrixProvider(localToDevice, true) {} |
| |
| // These should return the "same" matrix, as either a 3x3 or 4x4. Most sites in Skia still |
| // call localToDevice, and operate on SkMatrix. |
| const SkMatrix& localToDevice() const { return fLocalToDevice33; } |
| const SkM44& localToDevice44() const { return fLocalToDevice; } |
| |
| bool localToDeviceHitsPixelCenters() const { return fHitsPixelCenters; } |
| |
| protected: |
| SkMatrixProvider(const SkMatrix& localToDevice, bool hitsPixelCenters) |
| : fLocalToDevice(localToDevice) |
| , fLocalToDevice33(localToDevice) |
| , fHitsPixelCenters(hitsPixelCenters) {} |
| |
| SkMatrixProvider(const SkM44& localToDevice, bool hitsPixelCenters) |
| : fLocalToDevice(localToDevice) |
| , fLocalToDevice33(localToDevice.asM33()) |
| , fHitsPixelCenters(hitsPixelCenters) {} |
| |
| private: |
| friend class SkBaseDevice; |
| |
| SkM44 fLocalToDevice; |
| SkMatrix fLocalToDevice33; // Cached SkMatrix version of above, for legacy usage |
| const bool fHitsPixelCenters; |
| }; |
| |
| // Logically, this is equivalent to just making a new SkMatrixProvider, but we keep it distinct. |
| // This is for cases where there is an existing matrix provider, but we're replacing the |
| // local-to-device. In that scenario, we can't guarantee that we hit pixel centers anymore. |
| class SkOverrideDeviceMatrixProvider : public SkMatrixProvider { |
| public: |
| SkOverrideDeviceMatrixProvider(const SkMatrix& localToDevice) |
| : SkMatrixProvider(localToDevice, /*hitsPixelCenters=*/false) {} |
| }; |
| |
| class SkPostTranslateMatrixProvider : public SkMatrixProvider { |
| public: |
| SkPostTranslateMatrixProvider(const SkMatrixProvider& parent, SkScalar dx, SkScalar dy) |
| : SkMatrixProvider(SkM44::Translate(dx, dy) * parent.localToDevice44(), |
| parent.localToDeviceHitsPixelCenters()) {} |
| }; |
| |
| class SkPreConcatMatrixProvider : public SkMatrixProvider { |
| public: |
| SkPreConcatMatrixProvider(const SkMatrixProvider& parent, const SkMatrix& preMatrix) |
| : SkMatrixProvider(parent.localToDevice44() * SkM44(preMatrix), |
| parent.localToDeviceHitsPixelCenters()) {} |
| }; |
| |
| #endif |