blob: b28277c42cb582819140eaf8c7ba965ec6a64d65 [file] [log] [blame]
Stan Iliev021693b2016-10-17 16:26:15 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "LayerDrawable.h"
John Reck283bb462018-12-13 16:40:14 -080018#include <utils/MathUtils.h>
Greg Daniel45ec62b2017-01-04 14:27:00 -050019
Greg Danielac2d2322017-07-12 11:30:15 -040020#include "GrBackendSurface.h"
ramindanief54c032021-07-16 22:33:25 +000021#include "Matrix.h"
Derek Sollenbergerf87da672016-11-02 11:34:27 -040022#include "SkColorFilter.h"
Greg Daniel45ec62b2017-01-04 14:27:00 -050023#include "SkSurface.h"
Stan Iliev021693b2016-10-17 16:26:15 -040024#include "gl/GrGLTypes.h"
ramindanief54c032021-07-16 22:33:25 +000025#include "system/window.h"
Stan Iliev021693b2016-10-17 16:26:15 -040026
27namespace android {
28namespace uirenderer {
29namespace skiapipeline {
30
31void LayerDrawable::onDraw(SkCanvas* canvas) {
Derek Sollenbergerf5a370e2017-06-15 13:50:08 -040032 Layer* layer = mLayerUpdater->backingLayer();
33 if (layer) {
ramindanief54c032021-07-16 22:33:25 +000034 SkRect srcRect = layer->getCropRect();
35 DrawLayer(canvas->recordingContext(), canvas, layer, &srcRect, nullptr, true);
Derek Sollenbergerf5a370e2017-06-15 13:50:08 -040036 }
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050037}
38
Stan Iliev694f3e42019-07-29 17:00:49 -040039static inline SkScalar isIntegerAligned(SkScalar x) {
John Reck9a7c1922021-02-08 19:32:21 -050040 return MathUtils::isZero(roundf(x) - x);
Stan Iliev694f3e42019-07-29 17:00:49 -040041}
42
Stan Iliev134372d2019-07-10 16:46:09 -040043// Disable filtering when there is no scaling in screen coordinates and the corners have the same
44// fraction (for translate) or zero fraction (for any other rect-to-rect transform).
45static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, const SkRect& dstRect) {
46 if (!matrix.rectStaysRect()) return true;
47 SkRect dstDevRect = matrix.mapRect(dstRect);
48 float dstW, dstH;
Stan Iliev134372d2019-07-10 16:46:09 -040049 if (MathUtils::isZero(matrix.getScaleX()) && MathUtils::isZero(matrix.getScaleY())) {
50 // Has a 90 or 270 degree rotation, although total matrix may also have scale factors
51 // in m10 and m01. Those scalings are automatically handled by mapRect so comparing
52 // dimensions is sufficient, but swap width and height comparison.
53 dstW = dstDevRect.height();
54 dstH = dstDevRect.width();
Stan Iliev134372d2019-07-10 16:46:09 -040055 } else {
56 // Handle H/V flips or 180 rotation matrices. Axes may have been mirrored, but
57 // dimensions are still safe to compare directly.
58 dstW = dstDevRect.width();
59 dstH = dstDevRect.height();
Stan Iliev134372d2019-07-10 16:46:09 -040060 }
61 if (!(MathUtils::areEqual(dstW, srcRect.width()) &&
62 MathUtils::areEqual(dstH, srcRect.height()))) {
63 return true;
64 }
Stan Iliev019adb02019-09-26 14:29:48 -040065 // Device rect and source rect should be integer aligned to ensure there's no difference
66 // in how nearest-neighbor sampling is resolved.
67 return !(isIntegerAligned(srcRect.x()) &&
68 isIntegerAligned(srcRect.y()) &&
69 isIntegerAligned(dstDevRect.x()) &&
70 isIntegerAligned(dstDevRect.y()));
John Reck0aff62d2018-11-26 16:41:34 -080071}
72
Adlai Hollerf8c434e2020-07-27 11:42:45 -040073// TODO: Context arg probably doesn't belong here – do debug check at callsite instead.
74bool LayerDrawable::DrawLayer(GrRecordingContext* context,
75 SkCanvas* canvas,
76 Layer* layer,
77 const SkRect* srcRect,
78 const SkRect* dstRect,
Stan Iliev1a025a72018-09-05 16:35:11 -040079 bool useLayerTransform) {
Stan Ilieve9d00122017-09-19 12:07:10 -040080 if (context == nullptr) {
Sally Qi7e3f93b2021-07-15 00:00:54 +000081 ALOGD("Attempting to draw LayerDrawable into an unsupported surface");
Stan Ilieve9d00122017-09-19 12:07:10 -040082 return false;
83 }
Stan Iliev021693b2016-10-17 16:26:15 -040084 // transform the matrix based on the layer
ramindanief54c032021-07-16 22:33:25 +000085 const uint32_t transform = layer->getTextureTransform();
Stan Iliev564ca3e2018-09-04 22:00:00 +000086 sk_sp<SkImage> layerImage = layer->getImage();
Leon Scroggins III1a12ab22018-03-26 15:00:49 -040087 const int layerWidth = layer->getWidth();
88 const int layerHeight = layer->getHeight();
ramindanief54c032021-07-16 22:33:25 +000089 SkMatrix layerTransform = layer->getTransform();
Stan Iliev021693b2016-10-17 16:26:15 -040090 if (layerImage) {
Stan Ilievaac878f2018-07-12 16:53:59 -040091 SkMatrix matrix;
Stan Iliev1a025a72018-09-05 16:35:11 -040092 if (useLayerTransform) {
ramindanief54c032021-07-16 22:33:25 +000093 matrix = layerTransform;
Stan Ilievaac878f2018-07-12 16:53:59 -040094 }
Stan Iliev021693b2016-10-17 16:26:15 -040095 SkPaint paint;
Derek Sollenbergerc4fbada2016-11-07 16:05:41 -050096 paint.setAlpha(layer->getAlpha());
97 paint.setBlendMode(layer->getMode());
Derek Sollenbergerd01b5912018-10-19 15:55:33 -040098 paint.setColorFilter(layer->getColorFilter());
Stan Ilieva73b0be2017-10-06 10:16:58 -040099 const bool nonIdentityMatrix = !matrix.isIdentity();
100 if (nonIdentityMatrix) {
101 canvas->save();
102 canvas->concat(matrix);
103 }
ramindanief54c032021-07-16 22:33:25 +0000104 const SkMatrix totalMatrix = canvas->getTotalMatrix();
Stan Iliev1a025a72018-09-05 16:35:11 -0400105 if (dstRect || srcRect) {
Leon Scroggins III1a12ab22018-03-26 15:00:49 -0400106 SkMatrix matrixInv;
107 if (!matrix.invert(&matrixInv)) {
108 matrixInv = matrix;
109 }
Stan Iliev1a025a72018-09-05 16:35:11 -0400110 SkRect skiaSrcRect;
ramindanief54c032021-07-16 22:33:25 +0000111 if (srcRect && !srcRect->isEmpty()) {
Stan Iliev1a025a72018-09-05 16:35:11 -0400112 skiaSrcRect = *srcRect;
113 } else {
ramindanief54c032021-07-16 22:33:25 +0000114 skiaSrcRect = (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
115 ? SkRect::MakeIWH(layerHeight, layerWidth)
116 : SkRect::MakeIWH(layerWidth, layerHeight);
Stan Iliev1a025a72018-09-05 16:35:11 -0400117 }
118 matrixInv.mapRect(&skiaSrcRect);
119 SkRect skiaDestRect;
ramindanief54c032021-07-16 22:33:25 +0000120 if (dstRect && !dstRect->isEmpty()) {
Stan Iliev1a025a72018-09-05 16:35:11 -0400121 skiaDestRect = *dstRect;
122 } else {
123 skiaDestRect = SkRect::MakeIWH(layerWidth, layerHeight);
124 }
Leon Scroggins III1a12ab22018-03-26 15:00:49 -0400125 matrixInv.mapRect(&skiaDestRect);
Mike Reed7994a312021-01-28 18:06:26 -0500126 SkSamplingOptions sampling(SkFilterMode::kNearest);
Stan Iliev134372d2019-07-10 16:46:09 -0400127 if (layer->getForceFilter() ||
128 shouldFilterRect(totalMatrix, skiaSrcRect, skiaDestRect)) {
Mike Reed7994a312021-01-28 18:06:26 -0500129 sampling = SkSamplingOptions(SkFilterMode::kLinear);
Stan Ilievaa0a3312018-10-19 15:26:08 -0400130 }
ramindanief54c032021-07-16 22:33:25 +0000131
132 const float px = skiaDestRect.centerX();
133 const float py = skiaDestRect.centerY();
134 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
135 matrix.postScale(-1.f, 1.f, px, py);
136 }
137 if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
138 matrix.postScale(1.f, -1.f, px, py);
139 }
140 if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
141 matrix.postRotate(90, 0, 0);
142 matrix.postTranslate(skiaDestRect.height(), 0);
143 }
144 auto constraint = SkCanvas::kFast_SrcRectConstraint;
145 if (srcRect && srcRect->isEmpty()) {
146 constraint = SkCanvas::kStrict_SrcRectConstraint;
147 }
148 matrix.postConcat(SkMatrix::MakeRectToRect(skiaSrcRect, skiaDestRect,
149 SkMatrix::kFill_ScaleToFit));
Mike Reed7994a312021-01-28 18:06:26 -0500150 canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
ramindanief54c032021-07-16 22:33:25 +0000151 constraint);
Leon Scroggins III1a12ab22018-03-26 15:00:49 -0400152 } else {
Stan Iliev134372d2019-07-10 16:46:09 -0400153 SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height());
Mike Reed7994a312021-01-28 18:06:26 -0500154 SkSamplingOptions sampling(SkFilterMode::kNearest);
Stan Iliev134372d2019-07-10 16:46:09 -0400155 if (layer->getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) {
Mike Reed7994a312021-01-28 18:06:26 -0500156 sampling = SkSamplingOptions(SkFilterMode::kLinear);
Stan Ilievaa0a3312018-10-19 15:26:08 -0400157 }
Mike Reed7994a312021-01-28 18:06:26 -0500158 canvas->drawImage(layerImage.get(), 0, 0, sampling, &paint);
Leon Scroggins III1a12ab22018-03-26 15:00:49 -0400159 }
Stan Ilieva73b0be2017-10-06 10:16:58 -0400160 // restore the original matrix
161 if (nonIdentityMatrix) {
162 canvas->restore();
163 }
Stan Iliev021693b2016-10-17 16:26:15 -0400164 }
Ben Wagner6b62ac02018-05-29 14:16:02 -0400165 return layerImage != nullptr;
Stan Iliev021693b2016-10-17 16:26:15 -0400166}
167
Chris Blume7b8a8082018-11-30 15:51:58 -0800168} // namespace skiapipeline
169} // namespace uirenderer
170} // namespace android