void SkMultiPictureDraw::DrawData::Reset(SkTDArray<DrawData>& data) { for (int i = 0; i < data.count(); ++i) { data[i].fPicture->unref(); data[i].fCanvas->unref(); delete data[i].fPaint; } data.rewind(); }
// 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]; } }
void ImGuiLayer::onPaint(SkSurface* surface) { // This causes ImGui to rebuild vertex/index data based on all immediate-mode commands // (widgets, etc...) that have been issued ImGui::Render(); // Then we fetch the most recent data, and convert it so we can render with Skia const ImDrawData* drawData = ImGui::GetDrawData(); SkTDArray<SkPoint> pos; SkTDArray<SkPoint> uv; SkTDArray<SkColor> color; auto canvas = surface->getCanvas(); for (int i = 0; i < drawData->CmdListsCount; ++i) { const ImDrawList* drawList = drawData->CmdLists[i]; // De-interleave all vertex data (sigh), convert to Skia types pos.rewind(); uv.rewind(); color.rewind(); for (int j = 0; j < drawList->VtxBuffer.size(); ++j) { const ImDrawVert& vert = drawList->VtxBuffer[j]; pos.push_back(SkPoint::Make(vert.pos.x, vert.pos.y)); uv.push_back(SkPoint::Make(vert.uv.x, vert.uv.y)); color.push_back(vert.col); } // ImGui colors are RGBA SkSwapRB(color.begin(), color.begin(), color.count()); int indexOffset = 0; // Draw everything with canvas.drawVertices... for (int j = 0; j < drawList->CmdBuffer.size(); ++j) { const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j]; SkAutoCanvasRestore acr(canvas, true); // TODO: Find min/max index for each draw, so we know how many vertices (sigh) if (drawCmd->UserCallback) { drawCmd->UserCallback(drawList, drawCmd); } else { intptr_t idIndex = (intptr_t)drawCmd->TextureId; if (idIndex < fSkiaWidgetFuncs.count()) { // Small image IDs are actually indices into a list of callbacks. We directly // examing the vertex data to deduce the image rectangle, then reconfigure the // canvas to be clipped and translated so that the callback code gets to use // Skia to render a widget in the middle of an ImGui panel. ImDrawIdx rectIndex = drawList->IdxBuffer[indexOffset]; SkPoint tl = pos[rectIndex], br = pos[rectIndex + 2]; canvas->clipRect(SkRect::MakeLTRB(tl.fX, tl.fY, br.fX, br.fY)); canvas->translate(tl.fX, tl.fY); fSkiaWidgetFuncs[idIndex](canvas); } else { SkPaint* paint = static_cast<SkPaint*>(drawCmd->TextureId); SkASSERT(paint); canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y, drawCmd->ClipRect.z, drawCmd->ClipRect.w)); auto vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, drawList->VtxBuffer.size(), pos.begin(), uv.begin(), color.begin(), drawCmd->ElemCount, drawList->IdxBuffer.begin() + indexOffset); canvas->drawVertices(vertices, SkBlendMode::kModulate, *paint); } indexOffset += drawCmd->ElemCount; } } } fSkiaWidgetFuncs.reset(); }
// 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]; } }