StatefulBaseRenderer.cpp revision d218a92c0afb8c0d98135b20b52ac87236e1c935
1/* 2 * Copyright (C) 2014 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 <SkCanvas.h> 18 19#include "StatefulBaseRenderer.h" 20 21namespace android { 22namespace uirenderer { 23 24StatefulBaseRenderer::StatefulBaseRenderer() : 25 mDirtyClip(false), mWidth(-1), mHeight(-1), 26 mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) { 27} 28 29void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop, 30 float clipRight, float clipBottom) { 31 mSnapshot = new Snapshot(mFirstSnapshot, 32 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 33 mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom); 34 mSnapshot->fbo = getTargetFbo(); 35 mSaveCount = 1; 36} 37 38void StatefulBaseRenderer::initializeViewport(int width, int height) { 39 mWidth = width; 40 mHeight = height; 41 42 mFirstSnapshot->height = height; 43 mFirstSnapshot->viewport.set(0, 0, width, height); 44} 45 46/////////////////////////////////////////////////////////////////////////////// 47// Save (layer) 48/////////////////////////////////////////////////////////////////////////////// 49 50/** 51 * Non-virtual implementation of save, guaranteed to save without side-effects 52 * 53 * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save 54 * stack, and ensures restoreToCount() doesn't call back into subclass overrides. 55 */ 56int StatefulBaseRenderer::saveSnapshot(int flags) { 57 mSnapshot = new Snapshot(mSnapshot, flags); 58 return mSaveCount++; 59} 60 61int StatefulBaseRenderer::save(int flags) { 62 return saveSnapshot(flags); 63} 64 65/** 66 * Non-virtual implementation of restore, guaranteed to restore without side-effects. 67 */ 68void StatefulBaseRenderer::restoreSnapshot() { 69 sp<Snapshot> toRemove = mSnapshot; 70 sp<Snapshot> toRestore = mSnapshot->previous; 71 72 mSaveCount--; 73 mSnapshot = toRestore; 74 75 // subclass handles restore implementation 76 onSnapshotRestored(*toRemove, *toRestore); 77} 78 79void StatefulBaseRenderer::restore() { 80 if (mSaveCount > 1) { 81 restoreSnapshot(); 82 } 83} 84 85void StatefulBaseRenderer::restoreToCount(int saveCount) { 86 if (saveCount < 1) saveCount = 1; 87 88 while (mSaveCount > saveCount) { 89 restoreSnapshot(); 90 } 91} 92 93/////////////////////////////////////////////////////////////////////////////// 94// Matrix 95/////////////////////////////////////////////////////////////////////////////// 96 97void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const { 98 mSnapshot->transform->copyTo(*matrix); 99} 100 101void StatefulBaseRenderer::translate(float dx, float dy, float dz) { 102 mSnapshot->transform->translate(dx, dy, dz); 103} 104 105void StatefulBaseRenderer::rotate(float degrees) { 106 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 107} 108 109void StatefulBaseRenderer::scale(float sx, float sy) { 110 mSnapshot->transform->scale(sx, sy, 1.0f); 111} 112 113void StatefulBaseRenderer::skew(float sx, float sy) { 114 mSnapshot->transform->skew(sx, sy); 115} 116 117void StatefulBaseRenderer::setMatrix(const SkMatrix* matrix) { 118 if (matrix) { 119 mSnapshot->transform->load(*matrix); 120 } else { 121 mSnapshot->transform->loadIdentity(); 122 } 123} 124 125void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) { 126 mSnapshot->transform->load(matrix); 127} 128 129void StatefulBaseRenderer::concatMatrix(const SkMatrix* matrix) { 130 mat4 transform(*matrix); 131 mSnapshot->transform->multiply(transform); 132} 133 134void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) { 135 mSnapshot->transform->multiply(matrix); 136} 137 138/////////////////////////////////////////////////////////////////////////////// 139// Clip 140/////////////////////////////////////////////////////////////////////////////// 141 142bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 143 if (CC_LIKELY(currentTransform()->rectToRect())) { 144 mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op); 145 return !mSnapshot->clipRect->isEmpty(); 146 } 147 148 SkPath path; 149 path.addRect(left, top, right, bottom); 150 151 return StatefulBaseRenderer::clipPath(&path, op); 152} 153 154bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) { 155 SkMatrix transform; 156 currentTransform()->copyTo(transform); 157 158 SkPath transformed; 159 path->transform(transform, &transformed); 160 161 SkRegion clip; 162 if (!mSnapshot->previous->clipRegion->isEmpty()) { 163 clip.setRegion(*mSnapshot->previous->clipRegion); 164 } else { 165 if (mSnapshot->previous == firstSnapshot()) { 166 clip.setRect(0, 0, getWidth(), getHeight()); 167 } else { 168 Rect* bounds = mSnapshot->previous->clipRect; 169 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); 170 } 171 } 172 173 SkRegion region; 174 region.setPath(transformed, clip); 175 176 mDirtyClip |= mSnapshot->clipRegionTransformed(region, op); 177 return !mSnapshot->clipRect->isEmpty(); 178} 179 180bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { 181 mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op); 182 return !mSnapshot->clipRect->isEmpty(); 183} 184 185/////////////////////////////////////////////////////////////////////////////// 186// Quick Rejection 187/////////////////////////////////////////////////////////////////////////////// 188 189/** 190 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with 191 * the clipRect. Does not modify the scissor. 192 * 193 * @param clipRequired if not null, will be set to true if element intersects clip 194 * (and wasn't rejected) 195 * 196 * @param snapOut if set, the geometry will be treated as having an AA ramp. 197 * See Rect::snapGeometryToPixelBoundaries() 198 */ 199bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, 200 float right, float bottom, bool* clipRequired, bool snapOut) const { 201 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 202 return true; 203 } 204 205 Rect r(left, top, right, bottom); 206 currentTransform()->mapRect(r); 207 r.snapGeometryToPixelBoundaries(snapOut); 208 209 Rect clipRect(*currentClipRect()); 210 clipRect.snapToPixelBoundaries(); 211 212 if (!clipRect.intersects(r)) return true; 213 214 // clip is required if geometry intersects clip rect 215 if (clipRequired) *clipRequired = !clipRect.contains(r); 216 return false; 217} 218 219/** 220 * Returns false if drawing won't be clipped out. 221 * 222 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the 223 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but 224 * rejection is still desired. 225 * 226 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information 227 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass 228 * rejection where precise rejection isn't important, or precise information isn't available. 229 */ 230bool StatefulBaseRenderer::quickRejectConservative(float left, float top, 231 float right, float bottom) const { 232 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 233 return true; 234 } 235 236 Rect r(left, top, right, bottom); 237 currentTransform()->mapRect(r); 238 r.roundOut(); // rounded out to be conservative 239 240 Rect clipRect(*currentClipRect()); 241 clipRect.snapToPixelBoundaries(); 242 243 if (!clipRect.intersects(r)) return true; 244 245 return false; 246} 247 248}; // namespace uirenderer 249}; // namespace android 250