1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you mPrimitiveFields.may not use this file except in compliance with the License. 6 * You mPrimitiveFields.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 "RenderProperties.h" 18 19 #include <utils/Trace.h> 20 21 #include <SkColorFilter.h> 22 #include <SkMatrix.h> 23 #include <SkPath.h> 24 #include <SkPathOps.h> 25 26 #include "Matrix.h" 27 #include "hwui/Canvas.h" 28 #include "utils/MathUtils.h" 29 30 namespace android { 31 namespace uirenderer { 32 33 LayerProperties::LayerProperties() { 34 reset(); 35 } 36 37 LayerProperties::~LayerProperties() { 38 setType(LayerType::None); 39 } 40 41 void LayerProperties::reset() { 42 mOpaque = false; 43 setFromPaint(nullptr); 44 } 45 46 bool LayerProperties::setColorFilter(SkColorFilter* filter) { 47 if (mColorFilter.get() == filter) return false; 48 mColorFilter = sk_ref_sp(filter); 49 return true; 50 } 51 52 bool LayerProperties::setFromPaint(const SkPaint* paint) { 53 bool changed = false; 54 changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint))); 55 changed |= setXferMode(PaintUtils::getBlendModeDirect(paint)); 56 changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr); 57 return changed; 58 } 59 60 LayerProperties& LayerProperties::operator=(const LayerProperties& other) { 61 setType(other.type()); 62 setOpaque(other.opaque()); 63 setAlpha(other.alpha()); 64 setXferMode(other.xferMode()); 65 setColorFilter(other.getColorFilter()); 66 return *this; 67 } 68 69 RenderProperties::ComputedFields::ComputedFields() : mTransformMatrix(nullptr) {} 70 71 RenderProperties::ComputedFields::~ComputedFields() { 72 delete mTransformMatrix; 73 } 74 75 RenderProperties::RenderProperties() : mStaticMatrix(nullptr), mAnimationMatrix(nullptr) {} 76 77 RenderProperties::~RenderProperties() { 78 delete mStaticMatrix; 79 delete mAnimationMatrix; 80 } 81 82 RenderProperties& RenderProperties::operator=(const RenderProperties& other) { 83 if (this != &other) { 84 mPrimitiveFields = other.mPrimitiveFields; 85 setStaticMatrix(other.getStaticMatrix()); 86 setAnimationMatrix(other.getAnimationMatrix()); 87 setCameraDistance(other.getCameraDistance()); 88 mLayerProperties = other.layerProperties(); 89 90 // Force recalculation of the matrix, since other's dirty bit may be clear 91 mPrimitiveFields.mMatrixOrPivotDirty = true; 92 updateMatrix(); 93 } 94 return *this; 95 } 96 97 static void dumpMatrix(std::ostream& output, std::string& indent, const char* label, 98 SkMatrix* matrix) { 99 if (matrix) { 100 output << indent << "(" << label << " " << matrix << ": "; 101 output << std::fixed << std::setprecision(2); 102 output << "[" << matrix->get(0) << " " << matrix->get(1) << " " << matrix->get(2) << "]"; 103 output << " [" << matrix->get(3) << " " << matrix->get(4) << " " << matrix->get(5) << "]"; 104 output << " [" << matrix->get(6) << " " << matrix->get(7) << " " << matrix->get(8) << "]"; 105 output << ")" << std::endl; 106 } 107 } 108 109 void RenderProperties::debugOutputProperties(std::ostream& output, const int level) const { 110 auto indent = std::string(level * 2, ' '); 111 if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) { 112 output << indent << "(Translate (left, top) " << mPrimitiveFields.mLeft << ", " 113 << mPrimitiveFields.mTop << ")" << std::endl; 114 } 115 dumpMatrix(output, indent, "ConcatMatrix (static)", mStaticMatrix); 116 dumpMatrix(output, indent, "ConcatMatrix (animation)", mAnimationMatrix); 117 118 output << std::fixed << std::setprecision(2); 119 if (hasTransformMatrix()) { 120 if (isTransformTranslateOnly()) { 121 output << indent << "(Translate " << getTranslationX() << ", " << getTranslationY() 122 << ", " << getZ() << ")" << std::endl; 123 } else { 124 dumpMatrix(output, indent, "ConcatMatrix ", mComputedFields.mTransformMatrix); 125 } 126 } 127 128 const bool isLayer = effectiveLayerType() != LayerType::None; 129 int clipFlags = getClippingFlags(); 130 if (mPrimitiveFields.mAlpha < 1 && !MathUtils::isZero(mPrimitiveFields.mAlpha)) { 131 if (isLayer) { 132 clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer 133 } 134 135 if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) { 136 // simply scale rendering content's alpha 137 output << indent << "(ScaleAlpha " << mPrimitiveFields.mAlpha << ")" << std::endl; 138 } else { 139 // savelayeralpha to create an offscreen buffer to apply alpha 140 Rect layerBounds(0, 0, getWidth(), getHeight()); 141 if (clipFlags) { 142 getClippingRectForFlags(clipFlags, &layerBounds); 143 clipFlags = 0; // all clipping done by savelayer 144 } 145 output << indent << "(SaveLayerAlpha " << (int)layerBounds.left << ", " 146 << (int)layerBounds.top << ", " << (int)layerBounds.right << ", " 147 << (int)layerBounds.bottom << ", " << (int)(mPrimitiveFields.mAlpha * 255) 148 << ", 0x" << std::hex << (SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer) 149 << ")" << std::dec << std::endl; 150 } 151 } 152 153 if (clipFlags) { 154 Rect clipRect; 155 getClippingRectForFlags(clipFlags, &clipRect); 156 output << indent << "(ClipRect " << (int)clipRect.left << ", " << (int)clipRect.top << ", " 157 << (int)clipRect.right << ", " << (int)clipRect.bottom << ")" << std::endl; 158 } 159 160 if (getRevealClip().willClip()) { 161 Rect bounds; 162 getRevealClip().getBounds(&bounds); 163 output << indent << "(Clip to reveal clip with bounds " << bounds.left << ", " << bounds.top 164 << ", " << bounds.right << ", " << bounds.bottom << ")" << std::endl; 165 } 166 167 auto& outline = mPrimitiveFields.mOutline; 168 if (outline.getShouldClip()) { 169 if (outline.isEmpty()) { 170 output << indent << "(Clip to empty outline)"; 171 } else if (outline.willClip()) { 172 const Rect& bounds = outline.getBounds(); 173 output << indent << "(Clip to outline with bounds " << bounds.left << ", " << bounds.top 174 << ", " << bounds.right << ", " << bounds.bottom << ")" << std::endl; 175 } 176 } 177 } 178 179 void RenderProperties::updateMatrix() { 180 if (mPrimitiveFields.mMatrixOrPivotDirty) { 181 if (!mComputedFields.mTransformMatrix) { 182 // only allocate a mPrimitiveFields.matrix if we have a complex transform 183 mComputedFields.mTransformMatrix = new SkMatrix(); 184 } 185 if (!mPrimitiveFields.mPivotExplicitlySet) { 186 mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f; 187 mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f; 188 } 189 SkMatrix* transform = mComputedFields.mTransformMatrix; 190 transform->reset(); 191 if (MathUtils::isZero(getRotationX()) && MathUtils::isZero(getRotationY())) { 192 transform->setTranslate(getTranslationX(), getTranslationY()); 193 transform->preRotate(getRotation(), getPivotX(), getPivotY()); 194 transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY()); 195 } else { 196 SkMatrix transform3D; 197 mComputedFields.mTransformCamera.save(); 198 transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY()); 199 mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX); 200 mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY); 201 mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation); 202 mComputedFields.mTransformCamera.getMatrix(&transform3D); 203 transform3D.preTranslate(-getPivotX(), -getPivotY()); 204 transform3D.postTranslate(getPivotX() + getTranslationX(), 205 getPivotY() + getTranslationY()); 206 transform->postConcat(transform3D); 207 mComputedFields.mTransformCamera.restore(); 208 } 209 mPrimitiveFields.mMatrixOrPivotDirty = false; 210 } 211 } 212 213 } /* namespace uirenderer */ 214 } /* namespace android */ 215