@@ -78,17 +78,29 @@ struct RasterCacheUtil {
7878 * @return SkMatrix the snapped transformation matrix.
7979 */
8080 static SkMatrix GetIntegralTransCTM (const SkMatrix& ctm) {
81- // Avoid integral snapping if the matrix has complex transformation to avoid
82- // the artifact observed in https://github.com/flutter/flutter/issues/41654.
83- if (!ctm.isScaleTranslate ()) {
84- return ctm;
85- }
86- SkMatrix result = ctm;
87- result[SkMatrix::kMTransX ] = SkScalarRoundToScalar (ctm.getTranslateX ());
88- result[SkMatrix::kMTransY ] = SkScalarRoundToScalar (ctm.getTranslateY ());
89- return result;
81+ SkMatrix integral;
82+ return ComputeIntegralTransCTM (ctm, &integral) ? integral : ctm;
9083 }
9184
85+ /* *
86+ * @brief Snap the translation components of the |in| matrix to integers
87+ * and store the snapped matrix in |out|.
88+ *
89+ * The snapping will only happen if the matrix only has scale and translation
90+ * transformations. This is used, along with GetRoundedOutDeviceBounds, to
91+ * ensure that the textures drawn by the raster cache are exactly aligned to
92+ * physical pixels. Any layers that participate in raster caching must align
93+ * themselves to physical pixels even when not cached to prevent a change in
94+ * apparent location if caching is later applied.
95+ *
96+ * The |out| matrix will not be modified if this method returns false.
97+ *
98+ * @param in the current transformation matrix.
99+ * @param out the storage for the snapped matrix.
100+ * @return true if the integral modification was needed, false otherwise.
101+ */
102+ static bool ComputeIntegralTransCTM (const SkMatrix& in, SkMatrix* out);
103+
92104 /* *
93105 * @brief Snap the translation components of the matrix to integers.
94106 *
@@ -103,31 +115,28 @@ struct RasterCacheUtil {
103115 * @return SkM44 the snapped transformation matrix.
104116 */
105117 static SkM44 GetIntegralTransCTM (const SkM44& ctm) {
106- // Avoid integral snapping if the matrix has complex transformation to avoid
107- // the artifact observed in https://github.com/flutter/flutter/issues/41654.
108- if (ctm.rc (0 , 1 ) != 0 || ctm.rc (0 , 2 ) != 0 ) {
109- // X multiplied by either Y or Z
110- return ctm;
111- }
112- if (ctm.rc (1 , 0 ) != 0 || ctm.rc (1 , 2 ) != 0 ) {
113- // Y multiplied by either X or Z
114- return ctm;
115- }
116- // We do not need to worry about the Z row unless the W row
117- // has perspective entries...
118- if (ctm.rc (3 , 0 ) != 0 || ctm.rc (3 , 1 ) != 0 || ctm.rc (3 , 2 ) != 0 ||
119- ctm.rc (3 , 3 ) != 1 ) {
120- // W not identity row, therefore perspective is applied
121- return ctm;
122- }
123-
124- SkM44 result = ctm;
125- result.setRC (0 , 3 , SkScalarRoundToScalar (ctm.rc (0 , 3 )));
126- result.setRC (1 , 3 , SkScalarRoundToScalar (ctm.rc (1 , 3 )));
127- // No need to worry about Z translation because it has no effect
128- // without perspective entries...
129- return result;
118+ SkM44 integral;
119+ return ComputeIntegralTransCTM (ctm, &integral) ? integral : ctm;
130120 }
121+
122+ /* *
123+ * @brief Snap the translation components of the |in| matrix to integers
124+ * and store the snapped matrix in |out|.
125+ *
126+ * The snapping will only happen if the matrix only has scale and translation
127+ * transformations. This is used, along with GetRoundedOutDeviceBounds, to
128+ * ensure that the textures drawn by the raster cache are exactly aligned to
129+ * physical pixels. Any layers that participate in raster caching must align
130+ * themselves to physical pixels even when not cached to prevent a change in
131+ * apparent location if caching is later applied.
132+ *
133+ * The |out| matrix will not be modified if this method returns false.
134+ *
135+ * @param in the current transformation matrix.
136+ * @param out the storage for the snapped matrix.
137+ * @return true if the integral modification was needed, false otherwise.
138+ */
139+ static bool ComputeIntegralTransCTM (const SkM44& in, SkM44* out);
131140};
132141
133142} // namespace flutter
0 commit comments