void SkRTree::insert(const SkRect boundsArray[], int N) { SkASSERT(0 == fCount); SkTDArray<Branch> branches; branches.setReserve(N); for (int i = 0; i < N; i++) { const SkRect& bounds = boundsArray[i]; if (bounds.isEmpty()) { continue; } Branch* b = branches.push(); b->fBounds = bounds; b->fOpIndex = i; } fCount = branches.count(); if (fCount) { if (1 == fCount) { fNodes.setReserve(1); Node* n = this->allocateNodeAtLevel(0); n->fNumChildren = 1; n->fChildren[0] = branches[0]; fRoot.fSubtree = n; fRoot.fBounds = branches[0].fBounds; } else { fNodes.setReserve(CountNodes(fCount, fAspectRatio)); fRoot = this->bulkLoad(&branches); } } }
void SkTileGrid::reserve(int opCount) { if (fXTiles * fYTiles == 0) { return; // A tileless tile grid is nonsensical, but happens in at least cc_unittests. } // If we assume every op we're about to try to insert() falls within our grid bounds, // then every op has to hit at least one tile. In fact, a quick scan over our small // SKP set shows that in the average SKP, each op hits two 256x256 tiles. // If we take those observations and further assume the ops are distributed evenly // across the picture, we get this guess for number of ops per tile: const int opsPerTileGuess = (2 * opCount) / (fXTiles * fYTiles); for (SkTDArray<unsigned>* tile = fTiles; tile != fTiles + (fXTiles * fYTiles); tile++) { tile->setReserve(opsPerTileGuess); } // In practice, this heuristic means we'll temporarily allocate about 30% more bytes // than if we made no setReserve() calls, but time spent in insert() drops by about 50%. }
// static void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages, SkPDFCatalog* catalog, SkTDArray<SkPDFDict*>* pageTree, SkPDFDict** rootNode) { // PDF wants a tree describing all the pages in the document. We arbitrary // choose 8 (kNodeSize) as the number of allowed children. The internal // nodes have type "Pages" with an array of children, a parent pointer, and // the number of leaves below the node as "Count." The leaves are passed // into the method, have type "Page" and need a parent pointer. This method // builds the tree bottom up, skipping internal nodes that would have only // one child. static const int kNodeSize = 8; SkAutoTUnref<SkPDFName> kidsName(new SkPDFName("Kids")); SkAutoTUnref<SkPDFName> countName(new SkPDFName("Count")); SkAutoTUnref<SkPDFName> parentName(new SkPDFName("Parent")); // curNodes takes a reference to its items, which it passes to pageTree. SkTDArray<SkPDFDict*> curNodes; curNodes.setReserve(pages.count()); for (int i = 0; i < pages.count(); i++) { SkSafeRef(pages[i]); curNodes.push(pages[i]); } // nextRoundNodes passes its references to nodes on to curNodes. SkTDArray<SkPDFDict*> nextRoundNodes; nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); int treeCapacity = kNodeSize; do { for (int i = 0; i < curNodes.count(); ) { if (i > 0 && i + 1 == curNodes.count()) { nextRoundNodes.push(curNodes[i]); break; } SkPDFDict* newNode = new SkPDFDict("Pages"); SkAutoTUnref<SkPDFObjRef> newNodeRef(new SkPDFObjRef(newNode)); SkAutoTUnref<SkPDFArray> kids(new SkPDFArray); kids->reserve(kNodeSize); int count = 0; for (; i < curNodes.count() && count < kNodeSize; i++, count++) { curNodes[i]->insert(parentName.get(), newNodeRef.get()); kids->append(new SkPDFObjRef(curNodes[i]))->unref(); // TODO(vandebo): put the objects in strict access order. // Probably doesn't matter because they are so small. if (curNodes[i] != pages[0]) { pageTree->push(curNodes[i]); // Transfer reference. catalog->addObject(curNodes[i], false); } else { SkSafeUnref(curNodes[i]); catalog->addObject(curNodes[i], true); } } // treeCapacity is the number of leaf nodes possible for the // current set of subtrees being generated. (i.e. 8, 64, 512, ...). // It is hard to count the number of leaf nodes in the current // subtree. However, by construction, we know that unless it's the // last subtree for the current depth, the leaf count will be // treeCapacity, otherwise it's what ever is left over after // consuming treeCapacity chunks. int pageCount = treeCapacity; if (i == curNodes.count()) { pageCount = ((pages.count() - 1) % treeCapacity) + 1; } newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); newNode->insert(kidsName.get(), kids.get()); nextRoundNodes.push(newNode); // Transfer reference. } curNodes = nextRoundNodes; nextRoundNodes.rewind(); treeCapacity *= kNodeSize; } while (curNodes.count() > 1); pageTree->push(curNodes[0]); // Transfer reference. catalog->addObject(curNodes[0], false); if (rootNode) { *rootNode = curNodes[0]; } }
bool TiledPictureRenderer::render(SkBitmap** out) { SkASSERT(fPicture != NULL); if (NULL == fPicture) { return false; } SkBitmap bitmap; if (out) { *out = SkNEW(SkBitmap); setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), SkScalarCeilToInt(fPicture->cullRect().height())); setup_bitmap(&bitmap, fTileWidth, fTileHeight); } bool success = true; if (fUseMultiPictureDraw) { SkMultiPictureDraw mpd; SkTDArray<SkSurface*> surfaces; surfaces.setReserve(fTileRects.count()); // Create a separate SkSurface/SkCanvas for each tile along with a // translated version of the skp (to mimic Chrome's behavior) and // feed all such pairs to the MultiPictureDraw. for (int i = 0; i < fTileRects.count(); ++i) { SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(), fTileRects[i].height()); *surfaces.append() = fCanvas->newSurface(ii); surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix()); SkPictureRecorder recorder; SkRTreeFactory bbhFactory; SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()), SkIntToScalar(fTileRects[i].height()), &bbhFactory, SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag); c->save(); SkMatrix mat; mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft), -SkIntToScalar(fTileRects[i].fTop)); c->setMatrix(mat); c->drawPicture(fPicture); c->restore(); SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording()); mpd.add(surfaces[i]->getCanvas(), xlatedPicture); } // Render all the buffered SkCanvases/SkPictures mpd.draw(); // Sort out the results and cleanup the allocated surfaces for (int i = 0; i < fTileRects.count(); ++i) { success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i); surfaces[i]->unref(); } } else { for (int i = 0; i < fTileRects.count(); ++i) { draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture); success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i); } } return success; }
// static void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages, SkPDFCatalog* catalog, SkTDArray<SkPDFDict*>* pageTree, SkPDFDict** rootNode) { // PDF wants a tree describing all the pages in the document. We arbitrary // choose 8 (kNodeSize) as the number of allowed children. The internal // nodes have type "Pages" with an array of children, a parent pointer, and // the number of leaves below the node as "Count." The leaves are passed // into the method, have type "Page" and need a parent pointer. This method // builds the tree bottom up, skipping internal nodes that would have only // one child. static const int kNodeSize = 8; SkRefPtr<SkPDFName> kidsName = new SkPDFName("Kids"); kidsName->unref(); // SkRefPtr and new both took a reference. SkRefPtr<SkPDFName> countName = new SkPDFName("Count"); countName->unref(); // SkRefPtr and new both took a reference. SkRefPtr<SkPDFName> parentName = new SkPDFName("Parent"); parentName->unref(); // SkRefPtr and new both took a reference. // curNodes takes a reference to its items, which it passes to pageTree. SkTDArray<SkPDFDict*> curNodes; curNodes.setReserve(pages.count()); for (int i = 0; i < pages.count(); i++) { SkSafeRef(pages[i]); curNodes.push(pages[i]); } // nextRoundNodes passes its references to nodes on to curNodes. SkTDArray<SkPDFDict*> nextRoundNodes; nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); int treeCapacity = kNodeSize; do { for (int i = 0; i < curNodes.count(); ) { if (i > 0 && i + 1 == curNodes.count()) { nextRoundNodes.push(curNodes[i]); break; } SkPDFDict* newNode = new SkPDFDict("Pages"); SkRefPtr<SkPDFObjRef> newNodeRef = new SkPDFObjRef(newNode); newNodeRef->unref(); // SkRefPtr and new both took a reference. SkRefPtr<SkPDFArray> kids = new SkPDFArray; kids->unref(); // SkRefPtr and new both took a reference. kids->reserve(kNodeSize); int count = 0; for (; i < curNodes.count() && count < kNodeSize; i++, count++) { curNodes[i]->insert(parentName.get(), newNodeRef.get()); kids->append(new SkPDFObjRef(curNodes[i]))->unref(); // TODO(vandebo): put the objects in strict access order. // Probably doesn't matter because they are so small. if (curNodes[i] != pages[0]) { pageTree->push(curNodes[i]); // Transfer reference. catalog->addObject(curNodes[i], false); } else { SkSafeUnref(curNodes[i]); catalog->addObject(curNodes[i], true); } } newNode->insert(kidsName.get(), kids.get()); int pageCount = treeCapacity; if (count < kNodeSize) { pageCount = pages.count() % treeCapacity; } newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); nextRoundNodes.push(newNode); // Transfer reference. } curNodes = nextRoundNodes; nextRoundNodes.rewind(); treeCapacity *= kNodeSize; } while (curNodes.count() > 1); pageTree->push(curNodes[0]); // Transfer reference. catalog->addObject(curNodes[0], false); if (rootNode) { *rootNode = curNodes[0]; } }