// Callers delete the ToC tree, so we re-create it from prerecorded // values (which is faster than re-creating it from html every time) DocTocItem *ChmModel::GetTocTree() { DocTocItem *root = NULL, **nextChild = &root; Vec<DocTocItem *> levels; int idCounter = 0; for (ChmTocTraceItem *ti = tocTrace->IterStart(); ti; ti = tocTrace->IterNext()) { ChmTocItem *item = new ChmTocItem(ti->title, ti->pageNo, ti->url); item->id = ++idCounter; // append the item at the correct level CrashIf(ti->level < 1); if ((size_t)ti->level <= levels.Count()) { levels.RemoveAt(ti->level, levels.Count() - ti->level); levels.Last()->AddSibling(item); } else { (*nextChild) = item; levels.Append(item); } nextChild = &item->child; } if (root) root->OpenSingleNode(); return root; }
UINT RenderCache::Paint(HDC hdc, RectI bounds, DisplayModel *dm, int pageNo, PageInfo *pageInfo, bool *renderOutOfDateCue) { assert(pageInfo->shown && 0.0 != pageInfo->visibleRatio); int rotation = dm->Rotation(); float zoom = dm->ZoomReal(); USHORT targetRes = GetTileRes(dm, pageNo); USHORT maxRes = GetMaxTileRes(dm, pageNo, rotation); if (maxRes < targetRes) maxRes = targetRes; Vec<TilePosition> queue; queue.Append(TilePosition(0, 0, 0)); UINT renderDelayMin = RENDER_DELAY_UNDEFINED; bool neededScaling = false; while (queue.Count() > 0) { TilePosition tile = queue.At(0); queue.RemoveAt(0); RectI tileOnScreen = GetTileOnScreen(dm->engine, pageNo, rotation, zoom, tile, pageInfo->pageOnScreen); tileOnScreen = pageInfo->pageOnScreen.Intersect(tileOnScreen); RectI isect = bounds.Intersect(tileOnScreen); if (isect.IsEmpty()) continue; bool isTargetRes = tile.res == targetRes; UINT renderDelay = PaintTile(hdc, isect, dm, pageNo, tile, tileOnScreen, isTargetRes, renderOutOfDateCue, isTargetRes ? &neededScaling : NULL); if (!(isTargetRes && 0 == renderDelay) && tile.res < maxRes) { queue.Append(TilePosition(tile.res + 1, tile.row * 2, tile.col * 2)); queue.Append(TilePosition(tile.res + 1, tile.row * 2, tile.col * 2 + 1)); queue.Append(TilePosition(tile.res + 1, tile.row * 2 + 1, tile.col * 2)); queue.Append(TilePosition(tile.res + 1, tile.row * 2 + 1, tile.col * 2 + 1)); } if (isTargetRes && renderDelay > 0) neededScaling = true; renderDelayMin = min(renderDelay, renderDelayMin); // paint tiles from left to right from top to bottom if (tile.res > 0 && queue.Count() > 0 && tile.res < queue.At(0).res) queue.Sort(cmpTilePosition); } #ifdef CONSERVE_MEMORY if (!neededScaling) { if (renderOutOfDateCue) *renderOutOfDateCue = false; // free tiles with different resolution TilePosition tile(targetRes, (USHORT)-1, 0); FreePage(dm, pageNo, &tile); } FreeNotVisible(); #endif return renderDelayMin; }
static bool ParseSimple(ParserState *state) { Vec<NestingInfo> stack; int parentNodeIdx = -1; char *s = state->curr; for (;;) { if (!*s) break; ParsedLine p; s = ParseSimpleLine(s, p); if (!s) return false; if (p.isComment) continue; while (stack.Count() > 0) { size_t pos = stack.Count() - 1; NestingInfo it = stack.At(pos); if (it.indent >= p.indent) { stack.RemoveAt(pos); } else { parentNodeIdx = it.nodeIdx; break; } } if (parentNodeIdx != -1 && 0 == stack.Count()) return false; int nodeIdx; MarkupNode *node = state->AllocNode(nodeIdx, parentNodeIdx); node->name = p.name; node->attributes = p.attributes; node->user = NULL; state->cb->NewNode(node); NestingInfo it; it.indent = p.indent; it.nodeIdx = nodeIdx; stack.Append(it); } return 0 == stack.Count(); }
virtual void Visit(const WCHAR *name, const WCHAR *url, int level) { int pageNo = CreatePageNoForURL(url); ChmTocItem *item = new ChmTocItem(str::Dup(name), pageNo, str::Dup(url)); item->id = ++idCounter; item->open = level == 1; // append the item at the correct level CrashIf(level < 1); if (!*root) { *root = item; lastItems.Append(*root); } else if ((size_t)level <= lastItems.Count()) { lastItems.RemoveAt(level, lastItems.Count() - level); lastItems.Last() = lastItems.Last()->next = item; } else { lastItems.Last()->child = item; lastItems.Append(item); } }
static void VecTest() { Vec<int> ints; assert(ints.Count() == 0); ints.Append(1); ints.Push(2); ints.InsertAt(0, -1); assert(ints.Count() == 3); assert(ints.At(0) == -1 && ints.At(1) == 1 && ints.At(2) == 2); assert(ints.At(0) == -1 && ints.Last() == 2); int last = ints.Pop(); assert(last == 2); assert(ints.Count() == 2); ints.Push(3); ints.RemoveAt(0); assert(ints.Count() == 2); assert(ints.At(0) == 1 && ints.At(1) == 3); ints.Reset(); assert(ints.Count() == 0); for (int i = 0; i < 1000; i++) { ints.Push(i); } assert(ints.Count() == 1000 && ints.At(500) == 500); ints.Remove(500); assert(ints.Count() == 999 && ints.At(500) == 501); last = ints.Pop(); assert(last == 999); ints.Append(last); assert(ints.AtPtr(501) == &ints.At(501)); { Vec<int> ints2(ints); assert(ints2.Count() == 999); assert(ints.LendData() != ints2.LendData()); ints.Remove(600); assert(ints.Count() < ints2.Count()); ints2 = ints; assert(ints2.Count() == 998); } { char buf[2] = {'a', '\0'}; str::Str<char> v(0); for (int i = 0; i < 7; i++) { v.Append(buf, 1); buf[0] = buf[0] + 1; } char *s = v.LendData(); assert(str::Eq("abcdefg", s)); assert(7 == v.Count()); v.Set("helo"); assert(4 == v.Count()); assert(str::Eq("helo", v.LendData())); } { str::Str<char> v(128); v.Append("boo", 3); assert(str::Eq("boo", v.LendData())); assert(v.Count() == 3); v.Append("fop"); assert(str::Eq("boofop", v.LendData())); assert(v.Count() == 6); v.RemoveAt(2, 3); assert(v.Count() == 3); assert(str::Eq("bop", v.LendData())); v.Append('a'); assert(v.Count() == 4); assert(str::Eq("bopa", v.LendData())); char *s = v.StealData(); assert(str::Eq("bopa", s)); free(s); assert(v.Count() == 0); } { str::Str<char> v(0); for (int i = 0; i < 32; i++) { assert(v.Count() == i * 6); v.Append("lambd", 5); if (i % 2 == 0) v.Append('a'); else v.Push('a'); } for (int i=1; i<=16; i++) { v.RemoveAt((16 - i) * 6, 6); assert(v.Count() == (32 - i) * 6); } v.RemoveAt(0, 6 * 15); assert(v.Count() == 6); char *s = v.LendData(); assert(str::Eq(s, "lambda")); s = v.StealData(); assert(str::Eq(s, "lambda")); free(s); assert(v.Count() == 0); v.Append("lambda"); assert(str::Eq(v.LendData(), "lambda")); char c = v.Pop(); assert(c == 'a'); assert(str::Eq(v.LendData(), "lambd")); } VecTestAppendFmt(); { Vec<PointI *> v; srand((unsigned int)time(NULL)); for (int i = 0; i < 128; i++) { v.Append(new PointI(i, i)); size_t pos = rand() % v.Count(); v.InsertAt(pos, new PointI(i, i)); } assert(v.Count() == 128 * 2); size_t idx = 0; for (PointI **p = v.IterStart(); p; p = v.IterNext()) { assert(idx == v.IterIdx()); ++idx; } while (v.Count() > 64) { size_t pos = rand() % v.Count(); PointI *f = v.At(pos); v.Remove(f); delete f; } DeleteVecMembers(v); } { Vec<int> v; v.Append(2); for (int i = 0; i < 500; i++) v.Append(4); v.At(250) = 5; v.Reverse(); assert(v.Count() == 501 && v.At(0) == 4 && v.At(249) == v.At(251) && v.At(250) == 5 && v.At(500) == 2); v.Remove(4); v.Reverse(); assert(v.Count() == 500 && v.At(0) == 2 && v.At(249) == v.At(251) && v.At(250) == 5 && v.At(499) == 4); } }
static bool ParseXml(ParserState *state) { Vec<XmlNestingInfo> stack; int parentIdx = -1; char *s = state->curr; for (;;) { XmlTagInfo tagInfo; SkipWhitespace(s); if (!*s) { if (parentIdx != -1) return false; if (stack.Count() > 0) return false; return true; } if (*s != '<') return false; s++; bool skipped; if (!SkipCommentOrProcesingInstr(s, skipped)) return false; if (skipped) continue; if (!ParseTag(s, tagInfo)) return false; if (TAG_CLOSE == tagInfo.type) { if (0 == stack.Count()) return false; size_t pos = stack.Count() - 1; XmlNestingInfo ni = stack.At(pos); stack.RemoveAt(pos); if (!str::Eq(ni.name, tagInfo.name)) return false; parentIdx = -1; if (stack.Count() > 0) { ni = stack.At(stack.Count() - 1); parentIdx = ni.nodeIdx; } continue; } int nodeIdx; MarkupNode *node = state->AllocNode(nodeIdx, parentIdx); node->name = tagInfo.name; node->attributes = tagInfo.attributes; node->user = NULL; state->cb->NewNode(node); if (TAG_OPEN == tagInfo.type) { XmlNestingInfo ni; ni.name = tagInfo.name; ni.nodeIdx = nodeIdx; stack.Push(ni); parentIdx = nodeIdx; } } }