Home | History | Annotate | Download | only in AndroidPathRenderer
      1 /*
      2  * Copyright 2012 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #define LOG_TAG "PathRenderer"
      9 #define LOG_NDEBUG 1
     10 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
     11 
     12 #define VERTEX_DEBUG 0
     13 
     14 #include <SkPath.h>
     15 #include <SkStrokeRec.h>
     16 
     17 #include <stdlib.h>
     18 #include <stdint.h>
     19 #include <sys/types.h>
     20 
     21 #include <SkTypes.h>
     22 #include <SkTraceEvent.h>
     23 #include <SkMatrix.h>
     24 #include <SkPoint.h>
     25 
     26 #ifdef VERBOSE
     27 #define ALOGV SkDebugf
     28 #else
     29 #define ALOGV(x, ...)
     30 #endif
     31 
     32 #include "AndroidPathRenderer.h"
     33 #include "Vertex.h"
     34 
     35 namespace android {
     36 namespace uirenderer {
     37 
     38 #define THRESHOLD 0.5f
     39 
     40 SkRect PathRenderer::ComputePathBounds(const SkPath& path, const SkPaint* paint) {
     41     SkRect bounds = path.getBounds();
     42     if (paint->getStyle() != SkPaint::kFill_Style) {
     43         float outset = paint->getStrokeWidth() * 0.5f;
     44         bounds.outset(outset, outset);
     45     }
     46     return bounds;
     47 }
     48 
     49 inline void computeInverseScales(const SkMatrix* transform, float &inverseScaleX, float& inverseScaleY) {
     50     if (transform && transform->getType() & (SkMatrix::kScale_Mask|SkMatrix::kAffine_Mask|SkMatrix::kPerspective_Mask)) {
     51         float m00 = transform->getScaleX();
     52         float m01 = transform->getSkewY();
     53         float m10 = transform->getSkewX();
     54         float m11 = transform->getScaleY();
     55         float scaleX = sk_float_sqrt(m00 * m00 + m01 * m01);
     56         float scaleY = sk_float_sqrt(m10 * m10 + m11 * m11);
     57         inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
     58         inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
     59     } else {
     60         inverseScaleX = 1.0f;
     61         inverseScaleY = 1.0f;
     62     }
     63 }
     64 
     65 inline void copyVertex(Vertex* destPtr, const Vertex* srcPtr) {
     66     Vertex::set(destPtr, srcPtr->position[0], srcPtr->position[1]);
     67 }
     68 
     69 inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) {
     70     AlphaVertex::set(destPtr, srcPtr->position[0], srcPtr->position[1], srcPtr->alpha);
     71 }
     72 
     73 /**
     74  * Produces a pseudo-normal for a vertex, given the normals of the two incoming lines. If the offset
     75  * from each vertex in a perimeter is calculated, the resultant lines connecting the offset vertices
     76  * will be offset by 1.0
     77  *
     78  * Note that we can't add and normalize the two vectors, that would result in a rectangle having an
     79  * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1)
     80  *
     81  * NOTE: assumes angles between normals 90 degrees or less
     82  */
     83 inline SkVector totalOffsetFromNormals(const SkVector& normalA, const SkVector& normalB) {
     84     SkVector pseudoNormal = normalA + normalB;
     85     pseudoNormal.scale(1.0f / (1.0f + sk_float_abs(normalA.dot(normalB))));
     86     return pseudoNormal;
     87 }
     88 
     89 inline void scaleOffsetForStrokeWidth(SkVector& offset, float halfStrokeWidth,
     90         float inverseScaleX, float inverseScaleY) {
     91     if (halfStrokeWidth == 0.0f) {
     92         // hairline - compensate for scale
     93         offset.fX *= 0.5f * inverseScaleX;
     94         offset.fY *= 0.5f * inverseScaleY;
     95     } else {
     96         offset.scale(halfStrokeWidth);
     97     }
     98 }
     99 
    100 static void getFillVerticesFromPerimeter(const SkTArray<Vertex, true>& perimeter, VertexBuffer* vertexBuffer) {
    101     Vertex* buffer = vertexBuffer->alloc<Vertex>(perimeter.count());
    102 
    103     int currentIndex = 0;
    104     // zig zag between all previous points on the inside of the hull to create a
    105     // triangle strip that fills the hull
    106     int srcAindex = 0;
    107     int srcBindex = perimeter.count() - 1;
    108     while (srcAindex <= srcBindex) {
    109         copyVertex(&buffer[currentIndex++], &perimeter[srcAindex]);
    110         if (srcAindex == srcBindex) break;
    111         copyVertex(&buffer[currentIndex++], &perimeter[srcBindex]);
    112         srcAindex++;
    113         srcBindex--;
    114     }
    115 }
    116 
    117 static void getStrokeVerticesFromPerimeter(const SkTArray<Vertex, true>& perimeter, float halfStrokeWidth,
    118         VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
    119     Vertex* buffer = vertexBuffer->alloc<Vertex>(perimeter.count() * 2 + 2);
    120 
    121     int currentIndex = 0;
    122     const Vertex* last = &(perimeter[perimeter.count() - 1]);
    123     const Vertex* current = &(perimeter[0]);
    124     SkVector lastNormal;
    125     lastNormal.set(current->position[1] - last->position[1],
    126                    last->position[0] - current->position[0]);
    127     lastNormal.normalize();
    128     for (int i = 0; i < perimeter.count(); i++) {
    129         const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1]);
    130         SkVector nextNormal;
    131         nextNormal.set(next->position[1] - current->position[1],
    132                        current->position[0] - next->position[0]);
    133         nextNormal.normalize();
    134 
    135         SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
    136         scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    137 
    138         Vertex::set(&buffer[currentIndex++],
    139                 current->position[0] + totalOffset.fX,
    140                 current->position[1] + totalOffset.fY);
    141 
    142         Vertex::set(&buffer[currentIndex++],
    143                 current->position[0] - totalOffset.fX,
    144                 current->position[1] - totalOffset.fY);
    145 
    146         last = current;
    147         current = next;
    148         lastNormal = nextNormal;
    149     }
    150 
    151     // wrap around to beginning
    152     copyVertex(&buffer[currentIndex++], &buffer[0]);
    153     copyVertex(&buffer[currentIndex++], &buffer[1]);
    154 }
    155 
    156 static void getStrokeVerticesFromUnclosedVertices(const SkTArray<Vertex, true>& vertices, float halfStrokeWidth,
    157         VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
    158     Vertex* buffer = vertexBuffer->alloc<Vertex>(vertices.count() * 2);
    159 
    160     int currentIndex = 0;
    161     const Vertex* current = &(vertices[0]);
    162     SkVector lastNormal;
    163     for (int i = 0; i < vertices.count() - 1; i++) {
    164         const Vertex* next = &(vertices[i + 1]);
    165         SkVector nextNormal;
    166         nextNormal.set(next->position[1] - current->position[1],
    167                        current->position[0] - next->position[0]);
    168         nextNormal.normalize();
    169 
    170         SkVector totalOffset;
    171         if (i == 0) {
    172             totalOffset = nextNormal;
    173         } else {
    174             totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
    175         }
    176         scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    177 
    178         Vertex::set(&buffer[currentIndex++],
    179                 current->position[0] + totalOffset.fX,
    180                 current->position[1] + totalOffset.fY);
    181 
    182         Vertex::set(&buffer[currentIndex++],
    183                 current->position[0] - totalOffset.fX,
    184                 current->position[1] - totalOffset.fY);
    185 
    186         current = next;
    187         lastNormal = nextNormal;
    188     }
    189 
    190     SkVector totalOffset = lastNormal;
    191     scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    192 
    193     Vertex::set(&buffer[currentIndex++],
    194             current->position[0] + totalOffset.fX,
    195             current->position[1] + totalOffset.fY);
    196     Vertex::set(&buffer[currentIndex++],
    197             current->position[0] - totalOffset.fX,
    198             current->position[1] - totalOffset.fY);
    199 #if VERTEX_DEBUG
    200     for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
    201         SkDebugf("point at %f %f", buffer[i].position[0], buffer[i].position[1]);
    202     }
    203 #endif
    204 }
    205 
    206 static void getFillVerticesFromPerimeterAA(const SkTArray<Vertex, true>& perimeter, VertexBuffer* vertexBuffer,
    207          float inverseScaleX, float inverseScaleY) {
    208     AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(perimeter.count() * 3 + 2);
    209 
    210     // generate alpha points - fill Alpha vertex gaps in between each point with
    211     // alpha 0 vertex, offset by a scaled normal.
    212     int currentIndex = 0;
    213     const Vertex* last = &(perimeter[perimeter.count() - 1]);
    214     const Vertex* current = &(perimeter[0]);
    215     SkVector lastNormal;
    216     lastNormal.set(current->position[1] - last->position[1],
    217                    last->position[0] - current->position[0]);
    218     lastNormal.normalize();
    219     for (int i = 0; i < perimeter.count(); i++) {
    220         const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1]);
    221         SkVector nextNormal;
    222         nextNormal.set(next->position[1] - current->position[1],
    223                        current->position[0] - next->position[0]);
    224         nextNormal.normalize();
    225 
    226         // AA point offset from original point is that point's normal, such that each side is offset
    227         // by .5 pixels
    228         SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
    229         totalOffset.fX *= 0.5f * inverseScaleX;
    230         totalOffset.fY *= 0.5f * inverseScaleY;
    231 
    232         AlphaVertex::set(&buffer[currentIndex++],
    233                 current->position[0] + totalOffset.fX,
    234                 current->position[1] + totalOffset.fY,
    235                 0.0f);
    236         AlphaVertex::set(&buffer[currentIndex++],
    237                 current->position[0] - totalOffset.fX,
    238                 current->position[1] - totalOffset.fY,
    239                 1.0f);
    240 
    241         last = current;
    242         current = next;
    243         lastNormal = nextNormal;
    244     }
    245 
    246     // wrap around to beginning
    247     copyAlphaVertex(&buffer[currentIndex++], &buffer[0]);
    248     copyAlphaVertex(&buffer[currentIndex++], &buffer[1]);
    249 
    250     // zig zag between all previous points on the inside of the hull to create a
    251     // triangle strip that fills the hull, repeating the first inner point to
    252     // create degenerate tris to start inside path
    253     int srcAindex = 0;
    254     int srcBindex = perimeter.count() - 1;
    255     while (srcAindex <= srcBindex) {
    256         copyAlphaVertex(&buffer[currentIndex++], &buffer[srcAindex * 2 + 1]);
    257         if (srcAindex == srcBindex) break;
    258         copyAlphaVertex(&buffer[currentIndex++], &buffer[srcBindex * 2 + 1]);
    259         srcAindex++;
    260         srcBindex--;
    261     }
    262 
    263 #if VERTEX_DEBUG
    264     for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
    265         SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
    266     }
    267 #endif
    268 }
    269 
    270 
    271 static void getStrokeVerticesFromUnclosedVerticesAA(const SkTArray<Vertex, true>& vertices, float halfStrokeWidth,
    272         VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
    273     AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(6 * vertices.count() + 2);
    274 
    275     // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
    276     // alpha value (TODO: support different X/Y scale)
    277     float maxAlpha = 1.0f;
    278     if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
    279             halfStrokeWidth * inverseScaleX < 0.5f) {
    280         maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
    281         halfStrokeWidth = 0.0f;
    282     }
    283 
    284     // there is no outer/inner here, using them for consistency with below approach
    285     int offset = 2 * (vertices.count() - 2);
    286     int currentAAOuterIndex = 2;
    287     int currentAAInnerIndex = 2 * offset + 5; // reversed
    288     int currentStrokeIndex = currentAAInnerIndex + 7;
    289 
    290     const Vertex* last = &(vertices[0]);
    291     const Vertex* current = &(vertices[1]);
    292     SkVector lastNormal;
    293     lastNormal.set(current->position[1] - last->position[1],
    294                    last->position[0] - current->position[0]);
    295     lastNormal.normalize();
    296 
    297     {
    298         // start cap
    299         SkVector totalOffset = lastNormal;
    300         SkVector AAOffset = totalOffset;
    301         AAOffset.fX *= 0.5f * inverseScaleX;
    302         AAOffset.fY *= 0.5f * inverseScaleY;
    303 
    304         SkVector innerOffset = totalOffset;
    305         scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    306         SkVector outerOffset = innerOffset + AAOffset;
    307         innerOffset -= AAOffset;
    308 
    309         // TODO: support square cap by changing this offset to incorporate halfStrokeWidth
    310         SkVector capAAOffset;
    311         capAAOffset.set(AAOffset.fY, -AAOffset.fX);
    312         AlphaVertex::set(&buffer[0],
    313                 last->position[0] + outerOffset.fX + capAAOffset.fX,
    314                 last->position[1] + outerOffset.fY + capAAOffset.fY,
    315                 0.0f);
    316         AlphaVertex::set(&buffer[1],
    317                 last->position[0] + innerOffset.fX - capAAOffset.fX,
    318                 last->position[1] + innerOffset.fY - capAAOffset.fY,
    319                 maxAlpha);
    320 
    321         AlphaVertex::set(&buffer[2 * offset + 6],
    322                 last->position[0] - outerOffset.fX + capAAOffset.fX,
    323                 last->position[1] - outerOffset.fY + capAAOffset.fY,
    324                 0.0f);
    325         AlphaVertex::set(&buffer[2 * offset + 7],
    326                 last->position[0] - innerOffset.fX - capAAOffset.fX,
    327                 last->position[1] - innerOffset.fY - capAAOffset.fY,
    328                 maxAlpha);
    329         copyAlphaVertex(&buffer[2 * offset + 8], &buffer[0]);
    330         copyAlphaVertex(&buffer[2 * offset + 9], &buffer[1]);
    331         copyAlphaVertex(&buffer[2 * offset + 10], &buffer[1]); // degenerate tris (the only two!)
    332         copyAlphaVertex(&buffer[2 * offset + 11], &buffer[2 * offset + 7]);
    333     }
    334 
    335     for (int i = 1; i < vertices.count() - 1; i++) {
    336         const Vertex* next = &(vertices[i + 1]);
    337         SkVector nextNormal;
    338         nextNormal.set(next->position[1] - current->position[1],
    339                        current->position[0] - next->position[0]);
    340         nextNormal.normalize();
    341 
    342         SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
    343         SkVector AAOffset = totalOffset;
    344         AAOffset.fX *= 0.5f * inverseScaleX;
    345         AAOffset.fY *= 0.5f * inverseScaleY;
    346 
    347         SkVector innerOffset = totalOffset;
    348         scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    349         SkVector outerOffset = innerOffset + AAOffset;
    350         innerOffset -= AAOffset;
    351 
    352         AlphaVertex::set(&buffer[currentAAOuterIndex++],
    353                 current->position[0] + outerOffset.fX,
    354                 current->position[1] + outerOffset.fY,
    355                 0.0f);
    356         AlphaVertex::set(&buffer[currentAAOuterIndex++],
    357                 current->position[0] + innerOffset.fX,
    358                 current->position[1] + innerOffset.fY,
    359                 maxAlpha);
    360 
    361         AlphaVertex::set(&buffer[currentStrokeIndex++],
    362                 current->position[0] + innerOffset.fX,
    363                 current->position[1] + innerOffset.fY,
    364                 maxAlpha);
    365         AlphaVertex::set(&buffer[currentStrokeIndex++],
    366                 current->position[0] - innerOffset.fX,
    367                 current->position[1] - innerOffset.fY,
    368                 maxAlpha);
    369 
    370         AlphaVertex::set(&buffer[currentAAInnerIndex--],
    371                 current->position[0] - innerOffset.fX,
    372                 current->position[1] - innerOffset.fY,
    373                 maxAlpha);
    374         AlphaVertex::set(&buffer[currentAAInnerIndex--],
    375                 current->position[0] - outerOffset.fX,
    376                 current->position[1] - outerOffset.fY,
    377                 0.0f);
    378 
    379         last = current;
    380         current = next;
    381         lastNormal = nextNormal;
    382     }
    383 
    384     {
    385         // end cap
    386         SkVector totalOffset = lastNormal;
    387         SkVector AAOffset = totalOffset;
    388         AAOffset.fX *= 0.5f * inverseScaleX;
    389         AAOffset.fY *= 0.5f * inverseScaleY;
    390 
    391         SkVector innerOffset = totalOffset;
    392         scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    393         SkVector outerOffset = innerOffset + AAOffset;
    394         innerOffset -= AAOffset;
    395 
    396         // TODO: support square cap by changing this offset to incorporate halfStrokeWidth
    397         SkVector capAAOffset;
    398         capAAOffset.set(-AAOffset.fY, AAOffset.fX);
    399 
    400         AlphaVertex::set(&buffer[offset + 2],
    401                 current->position[0] + outerOffset.fX + capAAOffset.fX,
    402                 current->position[1] + outerOffset.fY + capAAOffset.fY,
    403                 0.0f);
    404         AlphaVertex::set(&buffer[offset + 3],
    405                 current->position[0] + innerOffset.fX - capAAOffset.fX,
    406                 current->position[1] + innerOffset.fY - capAAOffset.fY,
    407                 maxAlpha);
    408 
    409         AlphaVertex::set(&buffer[offset + 4],
    410                 current->position[0] - outerOffset.fX + capAAOffset.fX,
    411                 current->position[1] - outerOffset.fY + capAAOffset.fY,
    412                 0.0f);
    413         AlphaVertex::set(&buffer[offset + 5],
    414                 current->position[0] - innerOffset.fX - capAAOffset.fX,
    415                 current->position[1] - innerOffset.fY - capAAOffset.fY,
    416                 maxAlpha);
    417 
    418         copyAlphaVertex(&buffer[vertexBuffer->getSize() - 2], &buffer[offset + 3]);
    419         copyAlphaVertex(&buffer[vertexBuffer->getSize() - 1], &buffer[offset + 5]);
    420     }
    421 
    422 #if VERTEX_DEBUG
    423     for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
    424         SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
    425     }
    426 #endif
    427 }
    428 
    429 
    430 static void getStrokeVerticesFromPerimeterAA(const SkTArray<Vertex, true>& perimeter, float halfStrokeWidth,
    431         VertexBuffer* vertexBuffer, float inverseScaleX, float inverseScaleY) {
    432     AlphaVertex* buffer = vertexBuffer->alloc<AlphaVertex>(6 * perimeter.count() + 8);
    433 
    434     // avoid lines smaller than hairline since they break triangle based sampling. instead reducing
    435     // alpha value (TODO: support different X/Y scale)
    436     float maxAlpha = 1.0f;
    437     if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
    438             halfStrokeWidth * inverseScaleX < 0.5f) {
    439         maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
    440         halfStrokeWidth = 0.0f;
    441     }
    442 
    443     int offset = 2 * perimeter.count() + 3;
    444     int currentAAOuterIndex = 0;
    445     int currentStrokeIndex = offset;
    446     int currentAAInnerIndex = offset * 2;
    447 
    448     const Vertex* last = &(perimeter[perimeter.count() - 1]);
    449     const Vertex* current = &(perimeter[0]);
    450     SkVector lastNormal;
    451     lastNormal.set(current->position[1] - last->position[1],
    452                    last->position[0] - current->position[0]);
    453     lastNormal.normalize();
    454     for (int i = 0; i < perimeter.count(); i++) {
    455         const Vertex* next = &(perimeter[i + 1 >= perimeter.count() ? 0 : i + 1]);
    456         SkVector nextNormal;
    457         nextNormal.set(next->position[1] - current->position[1],
    458                        current->position[0] - next->position[0]);
    459         nextNormal.normalize();
    460 
    461         SkVector totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
    462         SkVector AAOffset = totalOffset;
    463         AAOffset.fX *= 0.5f * inverseScaleX;
    464         AAOffset.fY *= 0.5f * inverseScaleY;
    465 
    466         SkVector innerOffset = totalOffset;
    467         scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY);
    468         SkVector outerOffset = innerOffset + AAOffset;
    469         innerOffset -= AAOffset;
    470 
    471         AlphaVertex::set(&buffer[currentAAOuterIndex++],
    472                 current->position[0] + outerOffset.fX,
    473                 current->position[1] + outerOffset.fY,
    474                 0.0f);
    475         AlphaVertex::set(&buffer[currentAAOuterIndex++],
    476                 current->position[0] + innerOffset.fX,
    477                 current->position[1] + innerOffset.fY,
    478                 maxAlpha);
    479 
    480         AlphaVertex::set(&buffer[currentStrokeIndex++],
    481                 current->position[0] + innerOffset.fX,
    482                 current->position[1] + innerOffset.fY,
    483                 maxAlpha);
    484         AlphaVertex::set(&buffer[currentStrokeIndex++],
    485                 current->position[0] - innerOffset.fX,
    486                 current->position[1] - innerOffset.fY,
    487                 maxAlpha);
    488 
    489         AlphaVertex::set(&buffer[currentAAInnerIndex++],
    490                 current->position[0] - innerOffset.fX,
    491                 current->position[1] - innerOffset.fY,
    492                 maxAlpha);
    493         AlphaVertex::set(&buffer[currentAAInnerIndex++],
    494                 current->position[0] - outerOffset.fX,
    495                 current->position[1] - outerOffset.fY,
    496                 0.0f);
    497 
    498         last = current;
    499         current = next;
    500         lastNormal = nextNormal;
    501     }
    502 
    503     // wrap each strip around to beginning, creating degenerate tris to bridge strips
    504     copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[0]);
    505     copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]);
    506     copyAlphaVertex(&buffer[currentAAOuterIndex++], &buffer[1]);
    507 
    508     copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset]);
    509     copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]);
    510     copyAlphaVertex(&buffer[currentStrokeIndex++], &buffer[offset + 1]);
    511 
    512     copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset]);
    513     copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset + 1]);
    514     // don't need to create last degenerate tri
    515 
    516 #if VERTEX_DEBUG
    517     for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) {
    518         SkDebugf("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha);
    519     }
    520 #endif
    521 }
    522 
    523 void PathRenderer::ConvexPathVertices(const SkPath &path, const SkStrokeRec& stroke, bool isAA,
    524         const SkMatrix* transform, VertexBuffer* vertexBuffer) {
    525 
    526     SkStrokeRec::Style style = stroke.getStyle();
    527 
    528     float inverseScaleX, inverseScaleY;
    529     computeInverseScales(transform, inverseScaleX, inverseScaleY);
    530 
    531     SkTArray<Vertex, true> tempVertices;
    532     float threshInvScaleX = inverseScaleX;
    533     float threshInvScaleY = inverseScaleY;
    534     if (style == SkStrokeRec::kStroke_Style) {
    535         // alter the bezier recursion threshold values we calculate in order to compensate for
    536         // expansion done after the path vertices are found
    537         SkRect bounds = path.getBounds();
    538         if (!bounds.isEmpty()) {
    539             threshInvScaleX *= bounds.width() / (bounds.width() + stroke.getWidth());
    540             threshInvScaleY *= bounds.height() / (bounds.height() + stroke.getWidth());
    541         }
    542     }
    543 
    544     // force close if we're filling the path, since fill path expects closed perimeter.
    545     bool forceClose = style != SkStrokeRec::kStroke_Style;
    546     bool wasClosed = ConvexPathPerimeterVertices(path, forceClose, threshInvScaleX * threshInvScaleX,
    547             threshInvScaleY * threshInvScaleY, &tempVertices);
    548 
    549     if (!tempVertices.count()) {
    550         // path was empty, return without allocating vertex buffer
    551         return;
    552     }
    553 
    554 #if VERTEX_DEBUG
    555     for (unsigned int i = 0; i < tempVertices.count(); i++) {
    556         SkDebugf("orig path: point at %f %f", tempVertices[i].position[0], tempVertices[i].position[1]);
    557     }
    558 #endif
    559 
    560     if (style == SkStrokeRec::kStroke_Style) {
    561         float halfStrokeWidth = stroke.getWidth() * 0.5f;
    562         if (!isAA) {
    563             if (wasClosed) {
    564                 getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer,
    565                         inverseScaleX, inverseScaleY);
    566             } else {
    567                 getStrokeVerticesFromUnclosedVertices(tempVertices, halfStrokeWidth, vertexBuffer,
    568                         inverseScaleX, inverseScaleY);
    569             }
    570 
    571         } else {
    572             if (wasClosed) {
    573                 getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer,
    574                         inverseScaleX, inverseScaleY);
    575             } else {
    576                 getStrokeVerticesFromUnclosedVerticesAA(tempVertices, halfStrokeWidth, vertexBuffer,
    577                         inverseScaleX, inverseScaleY);
    578             }
    579         }
    580     } else {
    581         // For kStrokeAndFill style, the path should be adjusted externally, as it will be treated as a fill here.
    582         if (!isAA) {
    583             getFillVerticesFromPerimeter(tempVertices, vertexBuffer);
    584         } else {
    585             getFillVerticesFromPerimeterAA(tempVertices, vertexBuffer, inverseScaleX, inverseScaleY);
    586         }
    587     }
    588 }
    589 
    590 
    591 static void pushToVector(SkTArray<Vertex, true>* vertices, float x, float y) {
    592     // TODO: make this not yuck
    593     vertices->push_back();
    594     Vertex* newVertex = &((*vertices)[vertices->count() - 1]);
    595     Vertex::set(newVertex, x, y);
    596 }
    597 
    598 bool PathRenderer::ConvexPathPerimeterVertices(const SkPath& path, bool forceClose,
    599         float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVertices) {
    600 
    601 
    602     // TODO: to support joins other than sharp miter, join vertices should be labelled in the
    603     // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
    604     SkPath::Iter iter(path, forceClose);
    605     SkPoint pts[4];
    606     SkPath::Verb v;
    607 
    608     while (SkPath::kDone_Verb != (v = iter.next(pts))) {
    609             switch (v) {
    610                 case SkPath::kMove_Verb:
    611                     pushToVector(outputVertices, pts[0].x(), pts[0].y());
    612                     ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
    613                     break;
    614                 case SkPath::kClose_Verb:
    615                     ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y());
    616                     break;
    617                 case SkPath::kLine_Verb:
    618                     ALOGV("kLine_Verb %f %f -> %f %f",
    619                             pts[0].x(), pts[0].y(),
    620                             pts[1].x(), pts[1].y());
    621 
    622                     pushToVector(outputVertices, pts[1].x(), pts[1].y());
    623                     break;
    624                 case SkPath::kQuad_Verb:
    625                     ALOGV("kQuad_Verb");
    626                     RecursiveQuadraticBezierVertices(
    627                             pts[0].x(), pts[0].y(),
    628                             pts[2].x(), pts[2].y(),
    629                             pts[1].x(), pts[1].y(),
    630                             sqrInvScaleX, sqrInvScaleY, outputVertices);
    631                     break;
    632                 case SkPath::kCubic_Verb:
    633                     ALOGV("kCubic_Verb");
    634                     RecursiveCubicBezierVertices(
    635                             pts[0].x(), pts[0].y(),
    636                             pts[1].x(), pts[1].y(),
    637                             pts[3].x(), pts[3].y(),
    638                             pts[2].x(), pts[2].y(),
    639                         sqrInvScaleX, sqrInvScaleY, outputVertices);
    640                     break;
    641                 default:
    642                     break;
    643             }
    644     }
    645 
    646     int size = outputVertices->count();
    647     if (size >= 2 && (*outputVertices)[0].position[0] == (*outputVertices)[size - 1].position[0] &&
    648             (*outputVertices)[0].position[1] == (*outputVertices)[size - 1].position[1]) {
    649         outputVertices->pop_back();
    650         return true;
    651     }
    652     return false;
    653 }
    654 
    655 void PathRenderer::RecursiveCubicBezierVertices(
    656         float p1x, float p1y, float c1x, float c1y,
    657         float p2x, float p2y, float c2x, float c2y,
    658         float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVertices) {
    659     float dx = p2x - p1x;
    660     float dy = p2y - p1y;
    661     float d1 = sk_float_abs((c1x - p2x) * dy - (c1y - p2y) * dx);
    662     float d2 = sk_float_abs((c2x - p2x) * dy - (c2y - p2y) * dx);
    663     float d = d1 + d2;
    664 
    665     // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
    666 
    667     if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
    668         // below thresh, draw line by adding endpoint
    669         pushToVector(outputVertices, p2x, p2y);
    670     } else {
    671         float p1c1x = (p1x + c1x) * 0.5f;
    672         float p1c1y = (p1y + c1y) * 0.5f;
    673         float p2c2x = (p2x + c2x) * 0.5f;
    674         float p2c2y = (p2y + c2y) * 0.5f;
    675 
    676         float c1c2x = (c1x + c2x) * 0.5f;
    677         float c1c2y = (c1y + c2y) * 0.5f;
    678 
    679         float p1c1c2x = (p1c1x + c1c2x) * 0.5f;
    680         float p1c1c2y = (p1c1y + c1c2y) * 0.5f;
    681 
    682         float p2c1c2x = (p2c2x + c1c2x) * 0.5f;
    683         float p2c1c2y = (p2c2y + c1c2y) * 0.5f;
    684 
    685         float mx = (p1c1c2x + p2c1c2x) * 0.5f;
    686         float my = (p1c1c2y + p2c1c2y) * 0.5f;
    687 
    688         RecursiveCubicBezierVertices(
    689                 p1x, p1y, p1c1x, p1c1y,
    690                 mx, my, p1c1c2x, p1c1c2y,
    691                 sqrInvScaleX, sqrInvScaleY, outputVertices);
    692         RecursiveCubicBezierVertices(
    693                 mx, my, p2c1c2x, p2c1c2y,
    694                 p2x, p2y, p2c2x, p2c2y,
    695                 sqrInvScaleX, sqrInvScaleY, outputVertices);
    696     }
    697 }
    698 
    699 void PathRenderer::RecursiveQuadraticBezierVertices(
    700         float ax, float ay,
    701         float bx, float by,
    702         float cx, float cy,
    703         float sqrInvScaleX, float sqrInvScaleY, SkTArray<Vertex, true>* outputVertices) {
    704     float dx = bx - ax;
    705     float dy = by - ay;
    706     float d = (cx - bx) * dy - (cy - by) * dx;
    707 
    708     if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
    709         // below thresh, draw line by adding endpoint
    710         pushToVector(outputVertices, bx, by);
    711     } else {
    712         float acx = (ax + cx) * 0.5f;
    713         float bcx = (bx + cx) * 0.5f;
    714         float acy = (ay + cy) * 0.5f;
    715         float bcy = (by + cy) * 0.5f;
    716 
    717         // midpoint
    718         float mx = (acx + bcx) * 0.5f;
    719         float my = (acy + bcy) * 0.5f;
    720 
    721         RecursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
    722                 sqrInvScaleX, sqrInvScaleY, outputVertices);
    723         RecursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
    724                 sqrInvScaleX, sqrInvScaleY, outputVertices);
    725     }
    726 }
    727 
    728 }; // namespace uirenderer
    729 }; // namespace android
    730