UINT RenderCache::PaintTiles(HDC hdc, RectI bounds, DisplayModel *dm, int pageNo, RectI pageOnScreen, USHORT tileRes, bool renderMissing, bool *renderOutOfDateCue, bool *renderedReplacement) { int rotation = dm->Rotation(); float zoom = dm->ZoomReal(); int tileCount = 1 << tileRes; TilePosition tile = { tileRes, 0, 0 }; UINT renderTimeMin = (UINT)-1; for (tile.row = 0; tile.row < tileCount; tile.row++) { for (tile.col = 0; tile.col < tileCount; tile.col++) { RectI tileOnScreen = GetTileOnScreen(dm->engine, pageNo, rotation, zoom, tile, pageOnScreen); tileOnScreen = pageOnScreen.Intersect(tileOnScreen); RectI isect = bounds.Intersect(tileOnScreen); if (!isect.IsEmpty()) { UINT renderTime = PaintTile(hdc, isect, dm, pageNo, tile, tileOnScreen, renderMissing, renderOutOfDateCue, renderedReplacement); renderTimeMin = min(renderTime, renderTimeMin); } } } return renderTimeMin; }
static void WinUtilTest() { ScopedCom comScope; { char *string = "abcde"; size_t stringSize = 5, len; ScopedComPtr<IStream> stream(CreateStreamFromData(string, stringSize)); assert(stream); char *data = (char *)GetDataFromStream(stream, &len); assert(data && stringSize == len && str::Eq(data, string)); free(data); } { WCHAR *string = L"abcde"; size_t stringSize = 10, len; ScopedComPtr<IStream> stream(CreateStreamFromData(string, stringSize)); assert(stream); WCHAR *data = (WCHAR *)GetDataFromStream(stream, &len); assert(data && stringSize == len && str::Eq(data, string)); free(data); } { RectI oneScreen = GetFullscreenRect(NULL); RectI allScreens = GetVirtualScreenRect(); assert(allScreens.Intersect(oneScreen) == oneScreen); } }
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 void RemoveDialogItem(HWND hDlg, int itemId, int prevId=0) { HWND hItem = GetDlgItem(hDlg, itemId); RectI itemRc = MapRectToWindow(WindowRect(hItem), HWND_DESKTOP, hDlg); // shrink by the distance to the previous item HWND hPrev = prevId ? GetDlgItem(hDlg, prevId) : GetWindow(hItem, GW_HWNDPREV); RectI prevRc = MapRectToWindow(WindowRect(hPrev), HWND_DESKTOP, hDlg); int shrink = itemRc.y - prevRc.y + itemRc.dy - prevRc.dy; // move items below up, shrink container items and hide contained items for (HWND item = GetWindow(hDlg, GW_CHILD); item; item = GetWindow(item, GW_HWNDNEXT)) { RectI rc = MapRectToWindow(WindowRect(item), HWND_DESKTOP, hDlg); if (rc.y >= itemRc.y + itemRc.dy) // below MoveWindow(item, rc.x, rc.y - shrink, rc.dx, rc.dy, TRUE); else if (rc.Intersect(itemRc) == rc) // contained (or self) ShowWindow(item, SW_HIDE); else if (itemRc.Intersect(rc) == itemRc) // container MoveWindow(item, rc.x, rc.y, rc.dx, rc.dy - shrink, TRUE); } // shrink the dialog WindowRect dlgRc(hDlg); MoveWindow(hDlg, dlgRc.x, dlgRc.y, dlgRc.dx, dlgRc.dy - shrink, TRUE); }
static bool IsTileVisible(DisplayModel *dm, int pageNo, int rotation, float zoom, TilePosition tile, float fuzz=0) { if (!dm) return false; PageInfo *pageInfo = dm->GetPageInfo(pageNo); if (!dm->engine || !pageInfo) return false; RectI tileOnScreen = GetTileOnScreen(dm->engine, pageNo, rotation, zoom, tile, pageInfo->pageOnScreen); // consider nearby tiles visible depending on the fuzz factor tileOnScreen.x -= (int)(tileOnScreen.dx * fuzz * 0.5); tileOnScreen.dx = (int)(tileOnScreen.dx * (fuzz + 1)); tileOnScreen.y -= (int)(tileOnScreen.dy * fuzz * 0.5); tileOnScreen.dy = (int)(tileOnScreen.dy * (fuzz + 1)); RectI screen(PointI(), dm->viewPort.Size()); return !tileOnScreen.Intersect(screen).IsEmpty(); }
RenderedBitmap *DjVuEngineImpl::RenderBitmap(int pageNo, float zoom, int rotation, RectD *pageRect, RenderTarget target, AbortCookie **cookie_out) { ScopedCritSec scope(&gDjVuContext.lock); RectD pageRc = pageRect ? *pageRect : PageMediabox(pageNo); RectI screen = Transform(pageRc, pageNo, zoom, rotation).Round(); RectI full = Transform(PageMediabox(pageNo), pageNo, zoom, rotation).Round(); screen = full.Intersect(screen); ddjvu_page_t *page = ddjvu_page_create_by_pageno(doc, pageNo-1); if (!page) return NULL; int rotation4 = (((-rotation / 90) % 4) + 4) % 4; ddjvu_page_set_rotation(page, (ddjvu_page_rotation_t)rotation4); while (!ddjvu_page_decoding_done(page)) gDjVuContext.SpinMessageLoop(); if (ddjvu_page_decoding_error(page)) return NULL; bool isBitonal = DDJVU_PAGETYPE_BITONAL == ddjvu_page_get_type(page); ddjvu_format_t *fmt = ddjvu_format_create(isBitonal ? DDJVU_FORMAT_GREY8 : DDJVU_FORMAT_BGR24, 0, NULL); ddjvu_format_set_row_order(fmt, /* top_to_bottom */ TRUE); ddjvu_rect_t prect = { full.x, full.y, full.dx, full.dy }; ddjvu_rect_t rrect = { screen.x, 2 * full.y - screen.y + full.dy - screen.dy, screen.dx, screen.dy }; RenderedBitmap *bmp = NULL; int stride = ((screen.dx * (isBitonal ? 1 : 3) + 3) / 4) * 4; ScopedMem<char> bmpData(AllocArray<char>(stride * (screen.dy + 5))); if (bmpData) { #ifndef DEBUG ddjvu_render_mode_t mode = isBitonal ? DDJVU_RENDER_MASKONLY : DDJVU_RENDER_COLOR; #else // TODO: there seems to be a heap corruption in IW44Image.cpp // in debug builds when passing in DDJVU_RENDER_COLOR ddjvu_render_mode_t mode = DDJVU_RENDER_MASKONLY; #endif if (ddjvu_page_render(page, mode, &prect, &rrect, fmt, stride, bmpData.Get())) { bmp = new RenderedDjVuPixmap(bmpData, screen.Size(), isBitonal); AddUserAnnots(bmp, pageNo, zoom, rotation, screen); } } ddjvu_format_release(fmt); ddjvu_page_release(page); return bmp; }
static void WinUtilTest() { ScopedCom comScope; { char *string = "abcde"; size_t stringSize = 5, len; ScopedComPtr<IStream> stream(CreateStreamFromData(string, stringSize)); assert(stream); char *data = (char *)GetDataFromStream(stream, &len); assert(data && stringSize == len && str::Eq(data, string)); free(data); } { WCHAR *string = L"abcde"; size_t stringSize = 10, len; ScopedComPtr<IStream> stream(CreateStreamFromData(string, stringSize)); assert(stream); WCHAR *data = (WCHAR *)GetDataFromStream(stream, &len); assert(data && stringSize == len && str::Eq(data, string)); free(data); } { RectI oneScreen = GetFullscreenRect(NULL); RectI allScreens = GetVirtualScreenRect(); assert(allScreens.Intersect(oneScreen) == oneScreen); } { COLORREF c = AdjustLightness(RGB(255, 0, 0), 1.0f); assert(c == RGB(255, 0, 0)); c = AdjustLightness(RGB(255, 0, 0), 2.0f); assert(c == RGB(255, 255, 255)); c = AdjustLightness(RGB(255, 0, 0), 0.25f); assert(c == RGB(64, 0, 0)); c = AdjustLightness(RGB(226, 196, 226), 95 / 255.0f); assert(c == RGB(105, 52, 105)); c = AdjustLightness(RGB(255, 255, 255), 0.5f); assert(c == RGB(128, 128, 128)); } }
UINT RenderCache::Paint(HDC hdc, RectI bounds, DisplayModel* dm, int pageNo, PageInfo* pageInfo, bool* renderOutOfDateCue) { AssertCrash(pageInfo->shown && 0.0 != pageInfo->visibleRatio); if (!dm->ShouldCacheRendering(pageNo)) { int rotation = dm->GetRotation(); float zoom = dm->GetZoomReal(pageNo); bounds = pageInfo->pageOnScreen.Intersect(bounds); RectD area = bounds.Convert<double>(); area.Offset(-pageInfo->pageOnScreen.x, -pageInfo->pageOnScreen.y); area = dm->GetEngine()->Transform(area, pageNo, zoom, rotation, true); RenderedBitmap* bmp = dm->GetEngine()->RenderBitmap(pageNo, zoom, rotation, &area); bool success = bmp && bmp->GetBitmap() && bmp->StretchDIBits(hdc, bounds); delete bmp; return success ? 0 : RENDER_DELAY_FAILED; } int rotation = dm->GetRotation(); float zoom = dm->GetZoomReal(); 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.size() > 0) { TilePosition tile = queue.PopAt(0); RectI tileOnScreen = GetTileOnScreen(dm->GetEngine(), pageNo, rotation, zoom, tile, pageInfo->pageOnScreen); if (tileOnScreen.IsEmpty()) { // display an error message when only empty tiles should be drawn (i.e. on page loading errors) renderDelayMin = std::min(RENDER_DELAY_FAILED, renderDelayMin); continue; } 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 : nullptr); 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 = std::min(renderDelay, renderDelayMin); // paint tiles from left to right from top to bottom if (tile.res > 0 && queue.size() > 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; }