RectF MeasureTextQuick(Graphics *g, Font *f, const WCHAR *s, size_t len) { static Vec<Font *> fontCache; static Vec<bool> fixCache; RectF bbox; g->MeasureString(s, len, f, PointF(0, 0), &bbox); int idx = fontCache.Find(f); if (-1 == idx) { LOGFONTW lfw; Status ok = f->GetLogFontW(g, &lfw); bool isItalicOrMonospace = Ok != ok || lfw.lfItalic || str::Eq(lfw.lfFaceName, L"Courier New") || str::Find(lfw.lfFaceName, L"Consol") || str::EndsWith(lfw.lfFaceName, L"Mono") || str::EndsWith(lfw.lfFaceName, L"Typewriter"); fontCache.Append(f); fixCache.Append(isItalicOrMonospace); idx = (int)fontCache.Count() - 1; } // most documents look good enough with these adjustments if (!fixCache.At(idx)) { REAL correct = 0; for (size_t i = 0; i < len; i++) { switch (s[i]) { case 'i': case 'l': correct += 0.2f; break; case 't': case 'f': case 'I': correct += 0.1f; break; case '.': case ',': case '!': correct += 0.1f; break; } } bbox.Width *= (1.0f - correct / len) * 0.99f; } bbox.Height *= 0.95f; return bbox; }
Font *GetFont(const WCHAR *name, float size, FontStyle style) { int idx = cache.Find(Entry((WCHAR *)name, size, style)); if (idx != -1) return cache.At(idx).font; Font *font = ::new Font(name, size, style); if (!font) { // fall back to the default font, if a desired font can't be created font = ::new Font(L"Times New Roman", size, style); if (!font) { return cache.Count() > 0 ? cache.At(0).font : NULL; } } cache.Append(Entry(str::Dup(name), size, style, font)); return font; }
bool CbxEngineImpl::FinishLoadingCbz() { fileExt = L".cbz"; Vec<const WCHAR *> allFileNames; for (size_t idx = 0; idx < cbzFile->GetFileCount(); idx++) { const WCHAR *fileName = cbzFile->GetFileName(idx); // bail, if we accidentally try to load an XPS file if (fileName && str::StartsWith(fileName, L"_rels/.rels")) return false; if (fileName && ImageEngine::IsSupportedFile(fileName) && // OS X occasionally leaves metadata with image extensions !str::StartsWith(path::GetBaseName(fileName), L".")) { allFileNames.Append(fileName); } else { allFileNames.Append(NULL); } } assert(allFileNames.Count() == cbzFile->GetFileCount()); ScopedMem<char> metadata(cbzFile->GetFileData(L"ComicInfo.xml")); if (metadata) ParseComicInfoXml(metadata); metadata.Set(cbzFile->GetComment()); if (metadata) json::Parse(metadata, this); Vec<const WCHAR *> pageFileNames; for (const WCHAR **fn = allFileNames.IterStart(); fn; fn = allFileNames.IterNext()) { if (*fn) pageFileNames.Append(*fn); } pageFileNames.Sort(cmpAscii); for (const WCHAR **fn = pageFileNames.IterStart(); fn; fn = pageFileNames.IterNext()) { fileIdxs.Append(allFileNames.Find(*fn)); } assert(pageFileNames.Count() == fileIdxs.Count()); if (fileIdxs.Count() == 0) return false; pages.AppendBlanks(fileIdxs.Count()); mediaboxes.AppendBlanks(fileIdxs.Count()); return true; }