| 146 | } |
| 147 | |
| 148 | std::shared_ptr<GPUShapeProxy> ProxyProvider::createGPUShapeProxy(std::shared_ptr<Shape> shape, |
| 149 | AAType aaType, |
| 150 | const Rect& clipBounds, |
| 151 | uint32_t renderFlags) { |
| 152 | if (shape == nullptr) { |
| 153 | return nullptr; |
| 154 | } |
| 155 | Matrix drawingMatrix = {}; |
| 156 | auto isInverseFillType = shape->isInverseFillType(); |
| 157 | if (shape->type() == Shape::Type::Matrix && !isInverseFillType) { |
| 158 | auto matrixShape = std::static_pointer_cast<MatrixShape>(shape); |
| 159 | auto scales = matrixShape->matrix.getAxisScales(); |
| 160 | if (scales.x == scales.y) { |
| 161 | DEBUG_ASSERT(scales.x != 0); |
| 162 | drawingMatrix = matrixShape->matrix; |
| 163 | drawingMatrix.preScale(1.0f / scales.x, 1.0f / scales.x); |
| 164 | shape = Shape::ApplyMatrix(matrixShape->shape, Matrix::MakeScale(scales.x)); |
| 165 | } |
| 166 | } |
| 167 | auto shapeBounds = shape->getBounds(); |
| 168 | auto uniqueKey = shape->getUniqueKey(); |
| 169 | if (isInverseFillType) { |
| 170 | uniqueKey = |
| 171 | AppendClipBoundsKey(uniqueKey, clipBounds.makeOffset(-shapeBounds.left, -shapeBounds.top)); |
| 172 | } |
| 173 | if (aaType != AAType::None) { |
| 174 | // Add a 1-pixel outset to preserve antialiasing results. |
| 175 | shapeBounds.outset(1.0f, 1.0f); |
| 176 | } else { |
| 177 | static const auto NonAntialiasShapeType = UniqueID::Next(); |
| 178 | uniqueKey = UniqueKey::Append(uniqueKey, &NonAntialiasShapeType, 1); |
| 179 | } |
| 180 | auto bounds = isInverseFillType ? clipBounds : shapeBounds; |
| 181 | drawingMatrix.preTranslate(bounds.x(), bounds.y()); |
| 182 | static const auto TriangleShapeType = UniqueID::Next(); |
| 183 | static const auto TextureShapeType = UniqueID::Next(); |
| 184 | auto triangleKey = UniqueKey::Append(uniqueKey, &TriangleShapeType, 1); |
| 185 | // The triangle and texture proxies might be created by previous tasks that are still in progress. |
| 186 | // One of them might not have the corresponding resources in the cache yet, so we need to wrap |
| 187 | // both of them into the GPUShapeProxy. |
| 188 | auto triangleProxy = findOrWrapVertexBufferProxy(triangleKey); |
| 189 | auto textureKey = UniqueKey::Append(uniqueKey, &TextureShapeType, 1); |
| 190 | auto textureProxy = findOrWrapTextureProxy(textureKey); |
| 191 | if (triangleProxy != nullptr || textureProxy != nullptr) { |
| 192 | return std::make_shared<GPUShapeProxy>(drawingMatrix, std::move(triangleProxy), |
| 193 | std::move(textureProxy)); |
| 194 | } |
| 195 | auto width = static_cast<int>(ceilf(bounds.width())); |
| 196 | auto height = static_cast<int>(ceilf(bounds.height())); |
| 197 | shape = Shape::ApplyMatrix(std::move(shape), Matrix::MakeTrans(-bounds.x(), -bounds.y())); |
| 198 | auto rasterizer = std::make_unique<ShapeRasterizer>(width, height, std::move(shape), aaType); |
| 199 | std::unique_ptr<DataSource<ShapeBuffer>> dataSource = nullptr; |
| 200 | #ifdef TGFX_USE_THREADS |
| 201 | if (!(renderFlags & RenderFlags::DisableAsyncTask) && rasterizer->asyncSupport()) { |
| 202 | dataSource = DataSource<ShapeBuffer>::Async(std::move(rasterizer)); |
| 203 | } else { |
| 204 | dataSource = std::move(rasterizer); |
| 205 | } |
no test coverage detected