1#include "SkPictureRecord.h"
2#include "SkShape.h"
3#include "SkTSearch.h"
4
5#define MIN_WRITER_SIZE 16384
6#define HEAP_BLOCK_SIZE 4096
7
8SkPictureRecord::SkPictureRecord(uint32_t flags) :
9        fHeap(HEAP_BLOCK_SIZE), fWriter(MIN_WRITER_SIZE), fRecordFlags(flags) {
10    fBitmapIndex = fMatrixIndex = fPaintIndex = fRegionIndex = 1;
11#ifdef SK_DEBUG_SIZE
12    fPointBytes = fRectBytes = fTextBytes = 0;
13    fPointWrites = fRectWrites = fTextWrites = 0;
14#endif
15
16    fRestoreOffsetStack.setReserve(32);
17    fRestoreOffsetStack.push(0);
18
19    fPathHeap = NULL;   // lazy allocate
20}
21
22SkPictureRecord::~SkPictureRecord() {
23    reset();
24}
25
26///////////////////////////////////////////////////////////////////////////////
27
28int SkPictureRecord::save(SaveFlags flags) {
29    addDraw(SAVE);
30    addInt(flags);
31
32    fRestoreOffsetStack.push(0);
33
34    validate();
35    return this->INHERITED::save(flags);
36}
37
38int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
39                               SaveFlags flags) {
40    addDraw(SAVE_LAYER);
41    addRectPtr(bounds);
42    addPaintPtr(paint);
43    addInt(flags);
44
45    fRestoreOffsetStack.push(0);
46
47    validate();
48    /*  Don't actually call saveLayer, because that will try to allocate an
49        offscreen device (potentially very big) which we don't actually need
50        at this time (and may not be able to afford since during record our
51        clip starts out the size of the picture, which is often much larger
52        than the size of the actual device we'll use during playback).
53     */
54    return this->INHERITED::save(flags);
55}
56
57void SkPictureRecord::restore() {
58    // check for underflow
59    if (fRestoreOffsetStack.count() == 0) {
60        return;
61    }
62
63    // patch up the clip offsets
64    uint32_t restoreOffset = (uint32_t)fWriter.size();
65    uint32_t offset = fRestoreOffsetStack.top();
66    while (offset) {
67        uint32_t* peek = fWriter.peek32(offset);
68        offset = *peek;
69        *peek = restoreOffset;
70    }
71    fRestoreOffsetStack.pop();
72
73    addDraw(RESTORE);
74    validate();
75    return this->INHERITED::restore();
76}
77
78bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
79    addDraw(TRANSLATE);
80    addScalar(dx);
81    addScalar(dy);
82    validate();
83    return this->INHERITED::translate(dx, dy);
84}
85
86bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
87    addDraw(SCALE);
88    addScalar(sx);
89    addScalar(sy);
90    validate();
91    return this->INHERITED::scale(sx, sy);
92}
93
94bool SkPictureRecord::rotate(SkScalar degrees) {
95    addDraw(ROTATE);
96    addScalar(degrees);
97    validate();
98    return this->INHERITED::rotate(degrees);
99}
100
101bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
102    addDraw(SKEW);
103    addScalar(sx);
104    addScalar(sy);
105    validate();
106    return this->INHERITED::skew(sx, sy);
107}
108
109bool SkPictureRecord::concat(const SkMatrix& matrix) {
110    validate();
111    addDraw(CONCAT);
112    addMatrix(matrix);
113    validate();
114    return this->INHERITED::concat(matrix);
115}
116
117void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
118    validate();
119    addDraw(SET_MATRIX);
120    addMatrix(matrix);
121    validate();
122    this->INHERITED::setMatrix(matrix);
123}
124
125bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op) {
126    addDraw(CLIP_RECT);
127    addRect(rect);
128    addInt(op);
129
130    size_t offset = fWriter.size();
131    addInt(fRestoreOffsetStack.top());
132    fRestoreOffsetStack.top() = offset;
133
134    validate();
135    return this->INHERITED::clipRect(rect, op);
136}
137
138bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op) {
139    addDraw(CLIP_PATH);
140    addPath(path);
141    addInt(op);
142
143    size_t offset = fWriter.size();
144    addInt(fRestoreOffsetStack.top());
145    fRestoreOffsetStack.top() = offset;
146
147    validate();
148
149    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
150        return this->INHERITED::clipRect(path.getBounds(), op);
151    } else {
152        return this->INHERITED::clipPath(path, op);
153    }
154}
155
156bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
157    addDraw(CLIP_REGION);
158    addRegion(region);
159    addInt(op);
160
161    size_t offset = fWriter.size();
162    addInt(fRestoreOffsetStack.top());
163    fRestoreOffsetStack.top() = offset;
164
165    validate();
166    return this->INHERITED::clipRegion(region, op);
167}
168
169void SkPictureRecord::drawPaint(const SkPaint& paint) {
170    addDraw(DRAW_PAINT);
171    addPaint(paint);
172    validate();
173}
174
175void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
176                        const SkPaint& paint) {
177    addDraw(DRAW_POINTS);
178    addPaint(paint);
179    addInt(mode);
180    addInt(count);
181    fWriter.writeMul4(pts, count * sizeof(SkPoint));
182    validate();
183}
184
185void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
186    addDraw(DRAW_RECT);
187    addPaint(paint);
188    addRect(rect);
189    validate();
190}
191
192void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
193    addDraw(DRAW_PATH);
194    addPaint(paint);
195    addPath(path);
196    validate();
197}
198
199void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
200                        const SkPaint* paint = NULL) {
201    addDraw(DRAW_BITMAP);
202    addPaintPtr(paint);
203    addBitmap(bitmap);
204    addScalar(left);
205    addScalar(top);
206    validate();
207}
208
209void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
210                            const SkRect& dst, const SkPaint* paint) {
211    addDraw(DRAW_BITMAP_RECT);
212    addPaintPtr(paint);
213    addBitmap(bitmap);
214    addIRectPtr(src);  // may be null
215    addRect(dst);
216    validate();
217}
218
219void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
220                              const SkPaint* paint) {
221    addDraw(DRAW_BITMAP_MATRIX);
222    addPaintPtr(paint);
223    addBitmap(bitmap);
224    addMatrix(matrix);
225    validate();
226}
227
228void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
229                        const SkPaint* paint = NULL) {
230    addDraw(DRAW_SPRITE);
231    addPaintPtr(paint);
232    addBitmap(bitmap);
233    addInt(left);
234    addInt(top);
235    validate();
236}
237
238void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
239                                              SkScalar baselineY) {
240    SkPaint::FontMetrics metrics;
241    paint.getFontMetrics(&metrics);
242    SkRect bounds;
243    // construct a rect so we can see any adjustments from the paint.
244    // we use 0,1 for left,right, just so the rect isn't empty
245    bounds.set(0, metrics.fTop + baselineY,
246               SK_Scalar1, metrics.fBottom + baselineY);
247    (void)paint.computeFastBounds(bounds, &bounds);
248    // now record the top and bottom
249    addScalar(bounds.fTop);
250    addScalar(bounds.fBottom);
251}
252
253void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
254                      SkScalar y, const SkPaint& paint) {
255    bool fast = paint.canComputeFastBounds();
256
257    addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
258    addPaint(paint);
259    addText(text, byteLength);
260    addScalar(x);
261    addScalar(y);
262    if (fast) {
263        addFontMetricsTopBottom(paint, y);
264    }
265    validate();
266}
267
268void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
269                         const SkPoint pos[], const SkPaint& paint) {
270    size_t points = paint.countText(text, byteLength);
271    if (0 == points)
272        return;
273
274    bool canUseDrawH = true;
275    // check if the caller really should have used drawPosTextH()
276    {
277        const SkScalar firstY = pos[0].fY;
278        for (size_t index = 1; index < points; index++) {
279            if (pos[index].fY != firstY) {
280                canUseDrawH = false;
281                break;
282            }
283        }
284    }
285
286    bool fast = canUseDrawH && paint.canComputeFastBounds();
287
288    if (fast) {
289        addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
290    } else {
291        addDraw(canUseDrawH ? DRAW_POS_TEXT_H : DRAW_POS_TEXT);
292    }
293    addPaint(paint);
294    addText(text, byteLength);
295    addInt(points);
296
297#ifdef SK_DEBUG_SIZE
298    size_t start = fWriter.size();
299#endif
300    if (canUseDrawH) {
301        if (fast) {
302            addFontMetricsTopBottom(paint, pos[0].fY);
303        }
304        addScalar(pos[0].fY);
305        SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
306        for (size_t index = 0; index < points; index++)
307            *xptr++ = pos[index].fX;
308    }
309    else {
310        fWriter.writeMul4(pos, points * sizeof(SkPoint));
311    }
312#ifdef SK_DEBUG_SIZE
313    fPointBytes += fWriter.size() - start;
314    fPointWrites += points;
315#endif
316    validate();
317}
318
319void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
320                          const SkScalar xpos[], SkScalar constY,
321                          const SkPaint& paint) {
322    size_t points = paint.countText(text, byteLength);
323    if (0 == points)
324        return;
325
326    bool fast = paint.canComputeFastBounds();
327
328    addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
329    addPaint(paint);
330    addText(text, byteLength);
331    addInt(points);
332
333#ifdef SK_DEBUG_SIZE
334    size_t start = fWriter.size();
335#endif
336    if (fast) {
337        addFontMetricsTopBottom(paint, constY);
338    }
339    addScalar(constY);
340    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
341#ifdef SK_DEBUG_SIZE
342    fPointBytes += fWriter.size() - start;
343    fPointWrites += points;
344#endif
345    validate();
346}
347
348void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
349                            const SkPath& path, const SkMatrix* matrix,
350                            const SkPaint& paint) {
351    addDraw(DRAW_TEXT_ON_PATH);
352    addPaint(paint);
353    addText(text, byteLength);
354    addPath(path);
355    addMatrixPtr(matrix);
356    validate();
357}
358
359void SkPictureRecord::drawPicture(SkPicture& picture) {
360    addDraw(DRAW_PICTURE);
361    addPicture(picture);
362    validate();
363}
364
365void SkPictureRecord::drawShape(SkShape* shape) {
366    addDraw(DRAW_SHAPE);
367
368    int index = fShapes.find(shape);
369    if (index < 0) {    // not found
370        index = fShapes.count();
371        *fShapes.append() = shape;
372        shape->ref();
373    }
374    // follow the convention of recording a 1-based index
375    addInt(index + 1);
376    validate();
377}
378
379void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
380                          const SkPoint vertices[], const SkPoint texs[],
381                          const SkColor colors[], SkXfermode*,
382                          const uint16_t indices[], int indexCount,
383                          const SkPaint& paint) {
384    uint32_t flags = 0;
385    if (texs) {
386        flags |= DRAW_VERTICES_HAS_TEXS;
387    }
388    if (colors) {
389        flags |= DRAW_VERTICES_HAS_COLORS;
390    }
391    if (indexCount > 0) {
392        flags |= DRAW_VERTICES_HAS_INDICES;
393    }
394
395    addDraw(DRAW_VERTICES);
396    addPaint(paint);
397    addInt(flags);
398    addInt(vmode);
399    addInt(vertexCount);
400    addPoints(vertices, vertexCount);
401    if (flags & DRAW_VERTICES_HAS_TEXS) {
402        addPoints(texs, vertexCount);
403    }
404    if (flags & DRAW_VERTICES_HAS_COLORS) {
405        fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
406    }
407    if (flags & DRAW_VERTICES_HAS_INDICES) {
408        addInt(indexCount);
409        fWriter.writePad(indices, indexCount * sizeof(uint16_t));
410    }
411}
412
413void SkPictureRecord::drawData(const void* data, size_t length) {
414    addDraw(DRAW_DATA);
415    addInt(length);
416    fWriter.writePad(data, length);
417}
418
419///////////////////////////////////////////////////////////////////////////////
420
421void SkPictureRecord::reset() {
422    fPathHeap->safeUnref();
423    fPathHeap = NULL;
424
425    fBitmaps.reset();
426    fMatrices.reset();
427    fPaints.reset();
428    fPictureRefs.unrefAll();
429    fRegions.reset();
430    fShapes.safeUnrefAll();
431    fWriter.reset();
432    fHeap.reset();
433
434    fRestoreOffsetStack.setCount(1);
435    fRestoreOffsetStack.top() = 0;
436
437    fRCRecorder.reset();
438    fTFRecorder.reset();
439}
440
441void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
442    addInt(find(fBitmaps, bitmap));
443}
444
445void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
446    addMatrixPtr(&matrix);
447}
448
449void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
450    addInt(find(fMatrices, matrix));
451}
452
453void SkPictureRecord::addPaint(const SkPaint& paint) {
454    addPaintPtr(&paint);
455}
456
457void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
458    addInt(find(fPaints, paint));
459}
460
461void SkPictureRecord::addPath(const SkPath& path) {
462    if (NULL == fPathHeap) {
463        fPathHeap = SkNEW(SkPathHeap);
464    }
465    addInt(fPathHeap->append(path));
466}
467
468void SkPictureRecord::addPicture(SkPicture& picture) {
469    int index = fPictureRefs.find(&picture);
470    if (index < 0) {    // not found
471        index = fPictureRefs.count();
472        *fPictureRefs.append() = &picture;
473        picture.ref();
474    }
475    // follow the convention of recording a 1-based index
476    addInt(index + 1);
477}
478
479void SkPictureRecord::addPoint(const SkPoint& point) {
480#ifdef SK_DEBUG_SIZE
481    size_t start = fWriter.size();
482#endif
483    fWriter.writePoint(point);
484#ifdef SK_DEBUG_SIZE
485    fPointBytes += fWriter.size() - start;
486    fPointWrites++;
487#endif
488}
489
490void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
491    fWriter.writeMul4(pts, count * sizeof(SkPoint));
492#ifdef SK_DEBUG_SIZE
493    fPointBytes += count * sizeof(SkPoint);
494    fPointWrites++;
495#endif
496}
497
498void SkPictureRecord::addRect(const SkRect& rect) {
499#ifdef SK_DEBUG_SIZE
500    size_t start = fWriter.size();
501#endif
502    fWriter.writeRect(rect);
503#ifdef SK_DEBUG_SIZE
504    fRectBytes += fWriter.size() - start;
505    fRectWrites++;
506#endif
507}
508
509void SkPictureRecord::addRectPtr(const SkRect* rect) {
510    if (fWriter.writeBool(rect != NULL)) {
511        fWriter.writeRect(*rect);
512    }
513}
514
515void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
516    if (fWriter.writeBool(rect != NULL)) {
517        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
518    }
519}
520
521void SkPictureRecord::addRegion(const SkRegion& region) {
522    addInt(find(fRegions, region));
523}
524
525void SkPictureRecord::addText(const void* text, size_t byteLength) {
526#ifdef SK_DEBUG_SIZE
527    size_t start = fWriter.size();
528#endif
529    addInt(byteLength);
530    fWriter.writePad(text, byteLength);
531#ifdef SK_DEBUG_SIZE
532    fTextBytes += fWriter.size() - start;
533    fTextWrites++;
534#endif
535}
536
537///////////////////////////////////////////////////////////////////////////////
538
539int SkPictureRecord::find(SkTDArray<const SkFlatBitmap* >& bitmaps, const SkBitmap& bitmap) {
540    SkFlatBitmap* flat = SkFlatBitmap::Flatten(&fHeap, bitmap, fBitmapIndex,
541                                               &fRCRecorder);
542    int index = SkTSearch<SkFlatData>((const SkFlatData**) bitmaps.begin(),
543        bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
544    if (index >= 0) {
545        (void)fHeap.unalloc(flat);
546        return bitmaps[index]->index();
547    }
548    index = ~index;
549    *bitmaps.insert(index) = flat;
550    return fBitmapIndex++;
551}
552
553int SkPictureRecord::find(SkTDArray<const SkFlatMatrix* >& matrices, const SkMatrix* matrix) {
554    if (matrix == NULL)
555        return 0;
556    SkFlatMatrix* flat = SkFlatMatrix::Flatten(&fHeap, *matrix, fMatrixIndex);
557    int index = SkTSearch<SkFlatData>((const SkFlatData**) matrices.begin(),
558        matrices.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
559    if (index >= 0) {
560        (void)fHeap.unalloc(flat);
561        return matrices[index]->index();
562    }
563    index = ~index;
564    *matrices.insert(index) = flat;
565    return fMatrixIndex++;
566}
567
568int SkPictureRecord::find(SkTDArray<const SkFlatPaint* >& paints, const SkPaint* paint) {
569    if (paint == NULL) {
570        return 0;
571    }
572
573    SkFlatPaint* flat = SkFlatPaint::Flatten(&fHeap, *paint, fPaintIndex,
574                                             &fRCRecorder, &fTFRecorder);
575    int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(),
576        paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
577    if (index >= 0) {
578        (void)fHeap.unalloc(flat);
579        return paints[index]->index();
580    }
581
582    index = ~index;
583    *paints.insert(index) = flat;
584    return fPaintIndex++;
585}
586
587int SkPictureRecord::find(SkTDArray<const SkFlatRegion* >& regions, const SkRegion& region) {
588    SkFlatRegion* flat = SkFlatRegion::Flatten(&fHeap, region, fRegionIndex);
589    int index = SkTSearch<SkFlatData>((const SkFlatData**) regions.begin(),
590        regions.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
591    if (index >= 0) {
592        (void)fHeap.unalloc(flat);
593        return regions[index]->index();
594    }
595    index = ~index;
596    *regions.insert(index) = flat;
597    return fRegionIndex++;
598}
599
600#ifdef SK_DEBUG_DUMP
601void SkPictureRecord::dumpMatrices() {
602    int count = fMatrices.count();
603    SkMatrix defaultMatrix;
604    defaultMatrix.reset();
605    for (int index = 0; index < count; index++) {
606        const SkFlatMatrix* flatMatrix = fMatrices[index];
607        flatMatrix->dump();
608    }
609}
610
611void SkPictureRecord::dumpPaints() {
612    int count = fPaints.count();
613    for (int index = 0; index < count; index++)
614        fPaints[index]->dump();
615}
616#endif
617
618#ifdef SK_DEBUG_SIZE
619size_t SkPictureRecord::size() const {
620    size_t result = 0;
621    size_t sizeData;
622    bitmaps(&sizeData);
623    result += sizeData;
624    matrices(&sizeData);
625    result += sizeData;
626    paints(&sizeData);
627    result += sizeData;
628    paths(&sizeData);
629    result += sizeData;
630    pictures(&sizeData);
631    result += sizeData;
632    regions(&sizeData);
633    result += sizeData;
634    result += streamlen();
635    return result;
636}
637
638int SkPictureRecord::bitmaps(size_t* size) const {
639    size_t result = 0;
640    int count = fBitmaps.count();
641    for (int index = 0; index < count; index++)
642        result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
643    *size = result;
644    return count;
645}
646
647int SkPictureRecord::matrices(size_t* size) const {
648    int count = fMatrices.count();
649    *size = sizeof(fMatrices[0]) * count;
650    return count;
651}
652
653int SkPictureRecord::paints(size_t* size) const {
654    size_t result = 0;
655    int count = fPaints.count();
656    for (int index = 0; index < count; index++)
657        result += sizeof(fPaints[index]) + fPaints[index]->size();
658    *size = result;
659    return count;
660}
661
662int SkPictureRecord::paths(size_t* size) const {
663    size_t result = 0;
664    int count = fPaths.count();
665    for (int index = 0; index < count; index++)
666        result += sizeof(fPaths[index]) + fPaths[index]->size();
667    *size = result;
668    return count;
669}
670
671int SkPictureRecord::regions(size_t* size) const {
672    size_t result = 0;
673    int count = fRegions.count();
674    for (int index = 0; index < count; index++)
675        result += sizeof(fRegions[index]) + fRegions[index]->size();
676    *size = result;
677    return count;
678}
679
680size_t SkPictureRecord::streamlen() const {
681    return fWriter.size();
682}
683#endif
684
685#ifdef SK_DEBUG_VALIDATE
686void SkPictureRecord::validate() const {
687    validateBitmaps();
688    validateMatrices();
689    validatePaints();
690    validatePaths();
691    validatePictures();
692    validateRegions();
693}
694
695void SkPictureRecord::validateBitmaps() const {
696    int count = fBitmaps.count();
697    SkASSERT((unsigned) count < 0x1000);
698    for (int index = 0; index < count; index++) {
699        const SkFlatBitmap* bitPtr = fBitmaps[index];
700        SkASSERT(bitPtr);
701        bitPtr->validate();
702    }
703}
704
705void SkPictureRecord::validateMatrices() const {
706    int count = fMatrices.count();
707    SkASSERT((unsigned) count < 0x1000);
708    for (int index = 0; index < count; index++) {
709        const SkFlatMatrix* matrix = fMatrices[index];
710        SkASSERT(matrix);
711        matrix->validate();
712    }
713}
714
715void SkPictureRecord::validatePaints() const {
716    int count = fPaints.count();
717    SkASSERT((unsigned) count < 0x1000);
718    for (int index = 0; index < count; index++) {
719        const SkFlatPaint* paint = fPaints[index];
720        SkASSERT(paint);
721//            paint->validate();
722    }
723}
724
725void SkPictureRecord::validatePaths() const {
726    int count = fPaths.count();
727    SkASSERT((unsigned) count < 0x1000);
728    for (int index = 0; index < count; index++) {
729        const SkFlatPath* path = fPaths[index];
730        SkASSERT(path);
731        path->validate();
732    }
733}
734
735void SkPictureRecord::validateRegions() const {
736    int count = fRegions.count();
737    SkASSERT((unsigned) count < 0x1000);
738    for (int index = 0; index < count; index++) {
739        const SkFlatRegion* region = fRegions[index];
740        SkASSERT(region);
741        region->validate();
742    }
743}
744#endif
745
746