void OnSelectionStart(WindowInfo* win, int x, int y, WPARAM key) { UNUSED(key); CrashIf(!win->AsFixed()); DeleteOldSelectionInfo(win, true); win->selectionRect = RectI(x, y, 0, 0); win->showSelection = true; win->mouseAction = MouseAction::Selecting; bool isShift = IsShiftPressed(); bool isCtrl = IsCtrlPressed(); // Ctrl+drag forces a rectangular selection if (!isCtrl || isShift) { DisplayModel* dm = win->AsFixed(); int pageNo = dm->GetPageNoByPoint(PointI(x, y)); if (dm->ValidPageNo(pageNo)) { PointD pt = dm->CvtFromScreen(PointI(x, y), pageNo); dm->textSelection->StartAt(pageNo, pt.x, pt.y); win->mouseAction = MouseAction::SelectingText; } } SetCapture(win->hwndCanvas); SetTimer(win->hwndCanvas, SMOOTHSCROLL_TIMER_ID, SMOOTHSCROLL_DELAY_IN_MS, nullptr); win->RepaintAsync(); }
void OnSelectionEdgeAutoscroll(WindowInfo* win, int x, int y) { int dx = 0, dy = 0; if (x < SELECT_AUTOSCROLL_AREA_WIDTH) dx = -SELECT_AUTOSCROLL_STEP_LENGTH; else if (x > win->canvasRc.dx - SELECT_AUTOSCROLL_AREA_WIDTH) dx = SELECT_AUTOSCROLL_STEP_LENGTH; if (y < SELECT_AUTOSCROLL_AREA_WIDTH) dy = -SELECT_AUTOSCROLL_STEP_LENGTH; else if (y > win->canvasRc.dy - SELECT_AUTOSCROLL_AREA_WIDTH) dy = SELECT_AUTOSCROLL_STEP_LENGTH; CrashIf(NeedsSelectionEdgeAutoscroll(win, x, y) != (dx != 0 || dy != 0)); if (dx != 0 || dy != 0) { CrashIf(!win->AsFixed()); DisplayModel* dm = win->AsFixed(); PointI oldOffset = dm->GetViewPort().TL(); win->MoveDocBy(dx, dy); dx = dm->GetViewPort().x - oldOffset.x; dy = dm->GetViewPort().y - oldOffset.y; win->selectionRect.x -= dx; win->selectionRect.y -= dy; win->selectionRect.dx += dx; win->selectionRect.dy += dy; } }
void WindowInfo::MoveDocBy(int dx, int dy) { CrashIf(!this->AsFixed()); if (!this->AsFixed()) return; CrashIf(this->linkOnLastButtonDown); if (this->linkOnLastButtonDown) return; DisplayModel *dm = this->ctrl->AsFixed(); if (0 != dx) dm->ScrollXBy(dx); if (0 != dy) dm->ScrollYBy(dy, false); }
static void MakeRandomSelection(WindowInfo* win, int pageNo) { DisplayModel* dm = win->AsFixed(); if (!dm->ValidPageNo(pageNo)) pageNo = 1; if (!dm->ValidPageNo(pageNo)) return; // try a random position in the page int x = rand() % 640; int y = rand() % 480; if (dm->textSelection->IsOverGlyph(pageNo, x, y)) { dm->textSelection->StartAt(pageNo, x, y); dm->textSelection->SelectUpTo(pageNo, rand() % 640, rand() % 480); } }
static WindowInfo *LoadOnStartup(const WCHAR *filePath, CommandLineInfo& i, bool isFirstWin) { LoadArgs args(filePath); args.showWin = !(i.printDialog && i.exitWhenDone) && !gPluginMode; WindowInfo *win = LoadDocument(args); if (!win) return win; if (win->IsDocLoaded() && i.destName && isFirstWin) { win->linkHandler->GotoNamedDest(i.destName); } else if (win->IsDocLoaded() && i.pageNumber > 0 && isFirstWin) { if (win->ctrl->ValidPageNo(i.pageNumber)) win->ctrl->GoToPage(i.pageNumber, false); } if (i.hwndPluginParent) MakePluginWindow(*win, i.hwndPluginParent); if (!win->IsDocLoaded() || !isFirstWin) return win; if (i.enterPresentation || i.enterFullScreen) { if (i.enterPresentation && win->isFullScreen || i.enterFullScreen && win->presentation) ExitFullScreen(*win); EnterFullScreen(*win, i.enterPresentation); } if (i.startView != DM_AUTOMATIC) SwitchToDisplayMode(win, i.startView); if (i.startZoom != INVALID_ZOOM) ZoomToSelection(win, i.startZoom); if ((i.startScroll.x != -1 || i.startScroll.y != -1) && win->AsFixed()) { DisplayModel *dm = win->AsFixed(); ScrollState ss = dm->GetScrollState(); ss.x = i.startScroll.x; ss.y = i.startScroll.y; dm->SetScrollState(ss); } if (i.forwardSearchOrigin && i.forwardSearchLine && win->AsFixed() && win->AsFixed()->pdfSync) { UINT page; Vec<RectI> rects; ScopedMem<WCHAR> sourcePath(path::Normalize(i.forwardSearchOrigin)); int ret = win->AsFixed()->pdfSync->SourceToDoc(sourcePath, i.forwardSearchLine, 0, &page, rects); ShowForwardSearchResult(win, sourcePath, i.forwardSearchLine, 0, ret, page, rects); } return win; }
void StressTest::OnTimer(int timerIdGot) { CrashIf(timerId != timerIdGot); KillTimer(win->hwndFrame, timerId); if (!win->IsDocLoaded()) { if (!GoToNextFile()) { Finished(true); return; } TickTimer(); return; } // chm documents aren't rendered and we block until we show them // so we can assume previous page has been shown and go to next page if (!win->AsFixed()) { if (!GoToNextPage()) return; goto Next; } // For non-image files, we detect if a page was rendered by checking the cache // (but we don't wait more than 3 seconds). // Image files are always fully rendered in WM_PAINT, so we know the page // has already been rendered. DisplayModel *dm = win->AsFixed(); bool didRender = gRenderCache.Exists(dm, currPage, dm->GetRotation()); if (!didRender && dm->ShouldCacheRendering(currPage)) { double timeInMs = currPageRenderTime.GetTimeInMs(); if (timeInMs > 3.0 * 1000) { if (!GoToNextPage()) return; } } else if (!GoToNextPage()) { return; } MakeRandomSelection(win, currPage); Next: TickTimer(); }
void UpdateTextSelection(WindowInfo* win, bool select) { if (!win->AsFixed()) return; DisplayModel* dm = win->AsFixed(); if (select) { int pageNo = dm->GetPageNoByPoint(win->selectionRect.BR()); if (win->ctrl->ValidPageNo(pageNo)) { PointD pt = dm->CvtFromScreen(win->selectionRect.BR(), pageNo); dm->textSelection->SelectUpTo(pageNo, pt.x, pt.y); } } DeleteOldSelectionInfo(win); win->currentTab->selectionOnPage = SelectionOnPage::FromTextSelect(&dm->textSelection->result); win->showSelection = win->currentTab->selectionOnPage != nullptr; if (win->uia_provider) win->uia_provider->OnSelectionChanged(); }
void ZoomToSelection(WindowInfo* win, float factor, bool scrollToFit, bool relative) { PointI pt; bool zoomToPt = false; if (win->AsFixed()) { DisplayModel* dm = win->AsFixed(); // when not zooming to fit (which contradicts zooming to a specific point), ... if (!relative && (ZOOM_FIT_PAGE == factor || ZOOM_FIT_CONTENT == factor) && scrollToFit) { zoomToPt = false; } // either scroll towards the center of the current selection (if there is any) ... else if (win->showSelection && win->currentTab->selectionOnPage) { RectI selRect; for (SelectionOnPage& sel : *win->currentTab->selectionOnPage) { selRect = selRect.Union(sel.GetRect(dm)); } ClientRect rc(win->hwndCanvas); pt.x = 2 * selRect.x + selRect.dx - rc.dx / 2; pt.y = 2 * selRect.y + selRect.dy - rc.dy / 2; pt.x = limitValue(pt.x, selRect.x, selRect.x + selRect.dx); pt.y = limitValue(pt.y, selRect.y, selRect.y + selRect.dy); int pageNo = dm->GetPageNoByPoint(pt); zoomToPt = dm->ValidPageNo(pageNo) && dm->PageVisible(pageNo); } // or towards the top-left-most part of the first visible page else { int page = dm->FirstVisiblePageNo(); PageInfo* pageInfo = dm->GetPageInfo(page); if (pageInfo) { RectI visible = pageInfo->pageOnScreen.Intersect(win->canvasRc); pt = visible.TL(); int pageNo = dm->GetPageNoByPoint(pt); zoomToPt = !visible.IsEmpty() && dm->ValidPageNo(pageNo) && dm->PageVisible(pageNo); } } } win->ctrl->SetZoomVirtual(factor * (relative ? win->ctrl->GetZoomVirtual(true) : 1), zoomToPt ? &pt : nullptr); UpdateToolbarState(win); }
void OnSelectAll(WindowInfo* win, bool textOnly) { if (!HasPermission(Perm_CopySelection)) return; if (IsFocused(win->hwndFindBox) || IsFocused(win->hwndPageBox)) { Edit_SelectAll(GetFocus()); return; } if (win->AsChm()) { win->AsChm()->SelectAll(); return; } if (!win->AsFixed()) return; DisplayModel* dm = win->AsFixed(); if (textOnly) { int pageNo; for (pageNo = 1; !dm->GetPageInfo(pageNo)->shown; pageNo++) ; dm->textSelection->StartAt(pageNo, 0); for (pageNo = win->ctrl->PageCount(); !dm->GetPageInfo(pageNo)->shown; pageNo--) ; dm->textSelection->SelectUpTo(pageNo, -1); win->selectionRect = RectI::FromXY(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX); UpdateTextSelection(win); } else { DeleteOldSelectionInfo(win, true); win->selectionRect = RectI::FromXY(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX); win->currentTab->selectionOnPage = SelectionOnPage::FromRectangle(dm, win->selectionRect); } win->showSelection = win->currentTab->selectionOnPage != nullptr; win->RepaintAsync(); }
void CopySelectionToClipboard(WindowInfo* win) { if (!win->currentTab || !win->currentTab->selectionOnPage) return; CrashIf(win->currentTab->selectionOnPage->size() == 0 && win->mouseAction != MouseAction::SelectingText); if (win->currentTab->selectionOnPage->size() == 0) return; CrashIf(!win->AsFixed()); if (!win->AsFixed()) return; if (!OpenClipboard(nullptr)) return; EmptyClipboard(); DisplayModel* dm = win->AsFixed(); #ifndef DISABLE_DOCUMENT_RESTRICTIONS if (!dm->GetEngine()->AllowsCopyingText()) win->ShowNotification(_TR("Copying text was denied (copying as image only)")); else #endif if (!dm->GetEngine()->IsImageCollection()) { AutoFreeW selText; bool isTextSelection = dm->textSelection->result.len > 0; if (isTextSelection) { selText.Set(dm->textSelection->ExtractText(L"\r\n")); } else { WStrVec selections; for (SelectionOnPage& sel : *win->currentTab->selectionOnPage) { WCHAR* text = dm->GetTextInRegion(sel.pageNo, sel.rect); if (text) selections.Push(text); } selText.Set(selections.Join()); } // don't copy empty text if (!str::IsEmpty(selText.Get())) CopyTextToClipboard(selText, true); if (isTextSelection) { // don't also copy the first line of a text selection as an image CloseClipboard(); return; } } /* also copy a screenshot of the current selection to the clipboard */ SelectionOnPage* selOnPage = &win->currentTab->selectionOnPage->at(0); RenderedBitmap* bmp = dm->GetEngine()->RenderBitmap(selOnPage->pageNo, dm->GetZoomReal(), dm->GetRotation(), &selOnPage->rect, RenderTarget::Export); if (bmp) CopyImageToClipboard(bmp->GetBitmap(), true); delete bmp; CloseClipboard(); }
void OnMenuPrint(WindowInfo *win, bool waitForCompletion) { // we remember some printer settings per process static ScopedMem<DEVMODE> defaultDevMode; static PrintScaleAdv defaultScaleAdv = PrintScaleShrink; static bool defaultAsImage = false; bool printSelection = false; Vec<PRINTPAGERANGE> ranges; PRINTER_INFO_2 printerInfo = { 0 }; if (!HasPermission(Perm_PrinterAccess)) return; DisplayModel *dm = win->dm; assert(dm); if (!dm) return; if (!dm->engine || !dm->engine->AllowsPrinting()) return; if (win->IsChm()) { win->dm->AsChmEngine()->PrintCurrentPage(); return; } if (win->printThread) { int res = MessageBox(win->hwndFrame, _TR("Printing is still in progress. Abort and start over?"), _TR("Printing in progress."), MB_ICONEXCLAMATION | MB_YESNO | (IsUIRightToLeft() ? MB_RTLREADING : 0)); if (res == IDNO) return; } AbortPrinting(win); PRINTDLGEX pd; ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = win->hwndFrame; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; if (!win->selectionOnPage) pd.Flags |= PD_NOSELECTION; pd.nCopies = 1; /* by default print all pages */ pd.nPageRanges = 1; pd.nMaxPageRanges = MAXPAGERANGES; PRINTPAGERANGE *ppr = AllocArray<PRINTPAGERANGE>(MAXPAGERANGES); pd.lpPageRanges = ppr; ppr->nFromPage = 1; ppr->nToPage = dm->PageCount(); pd.nMinPage = 1; pd.nMaxPage = dm->PageCount(); pd.nStartPage = START_PAGE_GENERAL; Print_Advanced_Data advanced(PrintRangeAll, defaultScaleAdv, defaultAsImage); ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate); pd.lphPropertyPages = &hPsp; pd.nPropertyPages = 1; // restore remembered settings if (defaultDevMode) pd.hDevMode = GlobalMemDup(defaultDevMode.Get(), defaultDevMode.Get()->dmSize + defaultDevMode.Get()->dmDriverExtra); if (PrintDlgEx(&pd) != S_OK) { if (CommDlgExtendedError() != 0) { /* if PrintDlg was cancelled then CommDlgExtendedError is zero, otherwise it returns the error code, which we could look at here if we wanted. for now just warn the user that printing has stopped becasue of an error */ MessageBox(win->hwndFrame, _TR("Couldn't initialize printer"), _TR("Printing problem."), MB_ICONEXCLAMATION | MB_OK | (IsUIRightToLeft() ? MB_RTLREADING : 0)); } goto Exit; } if (pd.dwResultAction == PD_RESULT_PRINT || pd.dwResultAction == PD_RESULT_APPLY) { // remember settings for this process LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devMode) { defaultDevMode.Set((LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra)); GlobalUnlock(pd.hDevMode); } defaultScaleAdv = advanced.scale; defaultAsImage = advanced.asImage; } if (pd.dwResultAction != PD_RESULT_PRINT) goto Exit; if (pd.Flags & PD_CURRENTPAGE) { PRINTPAGERANGE pr = { dm->CurrentPageNo(), dm->CurrentPageNo() }; ranges.Append(pr); } else if (win->selectionOnPage && (pd.Flags & PD_SELECTION)) { printSelection = true; } else if (!(pd.Flags & PD_PAGENUMS)) { PRINTPAGERANGE pr = { 1, dm->PageCount() }; ranges.Append(pr); } else { assert(pd.nPageRanges > 0); for (DWORD i = 0; i < pd.nPageRanges; i++) ranges.Append(pd.lpPageRanges[i]); } LPDEVNAMES devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames); LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devNames) { printerInfo.pDriverName = (LPWSTR)devNames + devNames->wDriverOffset; printerInfo.pPrinterName = (LPWSTR)devNames + devNames->wDeviceOffset; printerInfo.pPortName = (LPWSTR)devNames + devNames->wOutputOffset; } PrintData *data = new PrintData(dm->engine, &printerInfo, devMode, ranges, advanced, dm->Rotation(), printSelection ? win->selectionOnPage : NULL); if (devNames) GlobalUnlock(pd.hDevNames); if (devMode) GlobalUnlock(pd.hDevMode); if (!waitForCompletion) PrintToDeviceOnThread(win, data); else { PrintToDevice(*data); delete data; } Exit: free(ppr); GlobalFree(pd.hDevNames); GlobalFree(pd.hDevMode); }
void LinkHandler::ScrollTo(PageDestination *dest) { assert(owner && owner->linkHandler == this); int pageNo = dest->GetDestPageNo(); if (pageNo <= 0) return; if (owner->dm->AsChmEngine()) { owner->dm->AsChmEngine()->GoToDestination(dest); return; } DisplayModel *dm = owner->dm; PointI scroll(-1, 0); RectD rect = dest->GetDestRect(); if (rect.IsEmpty()) { // PDF: /XYZ top left // scroll to rect.TL() PointD scrollD = dm->engine->Transform(rect.TL(), pageNo, dm->ZoomReal(), dm->Rotation()); scroll = scrollD.Convert<int>(); // default values for the coordinates mean: keep the current position if (DEST_USE_DEFAULT == rect.x) scroll.x = -1; if (DEST_USE_DEFAULT == rect.y) { PageInfo *pageInfo = dm->GetPageInfo(dm->CurrentPageNo()); scroll.y = -(pageInfo->pageOnScreen.y - dm->GetWindowMargin()->top); scroll.y = max(scroll.y, 0); // Adobe Reader never shows the previous page } } else if (rect.dx != DEST_USE_DEFAULT && rect.dy != DEST_USE_DEFAULT) { // PDF: /FitR left bottom right top RectD rectD = dm->engine->Transform(rect, pageNo, dm->ZoomReal(), dm->Rotation()); scroll = rectD.TL().Convert<int>(); // Rect<float> rectF = dm->engine->Transform(rect, pageNo, 1.0, dm->rotation()).Convert<float>(); // zoom = 100.0f * min(owner->canvasRc.dx / rectF.dx, owner->canvasRc.dy / rectF.dy); } else if (rect.y != DEST_USE_DEFAULT) { // PDF: /FitH top or /FitBH top PointD scrollD = dm->engine->Transform(rect.TL(), pageNo, dm->ZoomReal(), dm->Rotation()); scroll.y = max(scrollD.Convert<int>().y, 0); // Adobe Reader never shows the previous page // zoom = FitBH ? ZOOM_FIT_CONTENT : ZOOM_FIT_WIDTH } // else if (Fit || FitV) zoom = ZOOM_FIT_PAGE // else if (FitB || FitBV) zoom = ZOOM_FIT_CONTENT /* // ignore author-set zoom settings (at least as long as there's no way to overrule them) if (zoom != INVALID_ZOOM) { // TODO: adjust the zoom level before calculating the scrolling coordinates dm->zoomTo(zoom); UpdateToolbarState(owner); } // */ dm->GoToPage(pageNo, scroll.y, true, scroll.x); }
void LinkHandler::GotoLink(PageDestination *link) { assert(owner && owner->linkHandler == this); if (!link) return; if (!engine()) return; DisplayModel *dm = owner->dm; ScopedMem<WCHAR> path(link->GetDestValue()); PageDestType type = link->GetDestType(); if (Dest_ScrollTo == type) { // TODO: respect link->ld.gotor.new_window for PDF documents ? ScrollTo(link); } else if (Dest_LaunchURL == type) { if (!path) /* ignore missing URLs */; else if (!str::FindChar(path, ':')) { // treat relative URIs as file paths // LaunchFile will reject unsupported file types LaunchFile(path, NULL); } else { // LaunchBrowser will reject unsupported URI schemes LaunchBrowser(path); } } else if (Dest_LaunchEmbedded == type) { // open embedded PDF documents in a new window if (path && str::StartsWith(path.Get(), dm->FilePath())) { WindowInfo *newWin = FindWindowInfoByFile(path); if (!newWin) { LoadArgs args(path, owner); newWin = LoadDocument(args); } if (newWin) newWin->Focus(); } // offer to save other attachments to a file else { LinkSaver linkSaverTmp(*owner, path); link->SaveEmbedded(linkSaverTmp); } } else if (Dest_LaunchFile == type) { if (path) { // LaunchFile only opens files inside SumatraPDF // (except for allowed perceived file types) LaunchFile(path, link); } } // predefined named actions else if (Dest_NextPage == type) dm->GoToNextPage(0); else if (Dest_PrevPage == type) dm->GoToPrevPage(0); else if (Dest_FirstPage == type) dm->GoToFirstPage(); else if (Dest_LastPage == type) dm->GoToLastPage(); // Adobe Reader extensions to the spec, cf. http://www.tug.org/applications/hyperref/manual.html else if (Dest_FindDialog == type) PostMessage(owner->hwndFrame, WM_COMMAND, IDM_FIND_FIRST, 0); else if (Dest_FullScreen == type) PostMessage(owner->hwndFrame, WM_COMMAND, IDM_VIEW_PRESENTATION_MODE, 0); else if (Dest_GoBack == type) dm->Navigate(-1); else if (Dest_GoForward == type) dm->Navigate(1); else if (Dest_GoToPageDialog == type) PostMessage(owner->hwndFrame, WM_COMMAND, IDM_GOTO_PAGE, 0); else if (Dest_PrintDialog == type) PostMessage(owner->hwndFrame, WM_COMMAND, IDM_PRINT, 0); else if (Dest_SaveAsDialog == type) PostMessage(owner->hwndFrame, WM_COMMAND, IDM_SAVEAS, 0); else if (Dest_ZoomToDialog == type) PostMessage(owner->hwndFrame, WM_COMMAND, IDM_ZOOM_CUSTOM, 0); else CrashIf(Dest_None != type); }
void OnMenuPrint(WindowInfo *win, bool waitForCompletion) { // we remember some printer settings per process static ScopedMem<DEVMODE> defaultDevMode; static PrintScaleAdv defaultScaleAdv = PrintScaleShrink; static bool defaultAsImage = false; static bool hasDefaults = false; if (!hasDefaults) { hasDefaults = true; defaultAsImage = gGlobalPrefs->printerDefaults.printAsImage; if (str::EqI(gGlobalPrefs->printerDefaults.printScale, "fit")) defaultScaleAdv = PrintScaleFit; else if (str::EqI(gGlobalPrefs->printerDefaults.printScale, "none")) defaultScaleAdv = PrintScaleNone; } bool printSelection = false; Vec<PRINTPAGERANGE> ranges; PRINTER_INFO_2 printerInfo = { 0 }; if (!HasPermission(Perm_PrinterAccess)) return; if (win->AsChm()) { // the Print dialog allows access to the file system, so fall back // to printing the entire document without dialog if that isn't desired bool showUI = HasPermission(Perm_DiskAccess); win->AsChm()->PrintCurrentPage(showUI); return; } if (win->AsEbook()) { // TODO: use EbookEngine for printing? return; } CrashIf(!win->AsFixed()); if (!win->AsFixed()) return; DisplayModel *dm = win->AsFixed(); #ifndef DISABLE_DOCUMENT_RESTRICTIONS if (!dm->engine()->AllowsPrinting()) return; #endif if (win->printThread) { int res = MessageBox(win->hwndFrame, _TR("Printing is still in progress. Abort and start over?"), _TR("Printing in progress."), MB_ICONEXCLAMATION | MB_YESNO | MbRtlReadingMaybe()); if (res == IDNO) return; } AbortPrinting(win); // the Print dialog allows access to the file system, so fall back // to printing the entire document without dialog if that isn't desired if (!HasPermission(Perm_DiskAccess)) { PrintFile(dm->engine()); return; } PRINTDLGEX pd; ZeroMemory(&pd, sizeof(PRINTDLGEX)); pd.lStructSize = sizeof(PRINTDLGEX); pd.hwndOwner = win->hwndFrame; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE; if (!win->selectionOnPage) pd.Flags |= PD_NOSELECTION; pd.nCopies = 1; /* by default print all pages */ pd.nPageRanges = 1; pd.nMaxPageRanges = MAXPAGERANGES; PRINTPAGERANGE *ppr = AllocArray<PRINTPAGERANGE>(MAXPAGERANGES); pd.lpPageRanges = ppr; ppr->nFromPage = 1; ppr->nToPage = dm->PageCount(); pd.nMinPage = 1; pd.nMaxPage = dm->PageCount(); pd.nStartPage = START_PAGE_GENERAL; Print_Advanced_Data advanced(PrintRangeAll, defaultScaleAdv, defaultAsImage); ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate); pd.lphPropertyPages = &hPsp; pd.nPropertyPages = 1; // restore remembered settings if (defaultDevMode) { DEVMODE *p = defaultDevMode.Get(); pd.hDevMode = GlobalMemDup(p, p->dmSize + p->dmDriverExtra); } if (PrintDlgEx(&pd) != S_OK) { if (CommDlgExtendedError() != 0) { /* if PrintDlg was cancelled then CommDlgExtendedError is zero, otherwise it returns the error code, which we could look at here if we wanted. for now just warn the user that printing has stopped becasue of an error */ MessageBoxWarning(win->hwndFrame, _TR("Couldn't initialize printer"), _TR("Printing problem.")); } goto Exit; } if (pd.dwResultAction == PD_RESULT_PRINT || pd.dwResultAction == PD_RESULT_APPLY) { // remember settings for this process LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devMode) { defaultDevMode.Set((LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra)); GlobalUnlock(pd.hDevMode); } defaultScaleAdv = advanced.scale; defaultAsImage = advanced.asImage; } if (pd.dwResultAction != PD_RESULT_PRINT) goto Exit; if (pd.Flags & PD_CURRENTPAGE) { PRINTPAGERANGE pr = { dm->CurrentPageNo(), dm->CurrentPageNo() }; ranges.Append(pr); } else if (win->selectionOnPage && (pd.Flags & PD_SELECTION)) { printSelection = true; } else if (!(pd.Flags & PD_PAGENUMS)) { PRINTPAGERANGE pr = { 1, dm->PageCount() }; ranges.Append(pr); } else { assert(pd.nPageRanges > 0); for (DWORD i = 0; i < pd.nPageRanges; i++) ranges.Append(pd.lpPageRanges[i]); } LPDEVNAMES devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames); LPDEVMODE devMode = (LPDEVMODE)GlobalLock(pd.hDevMode); if (devNames) { printerInfo.pDriverName = (LPWSTR)devNames + devNames->wDriverOffset; printerInfo.pPrinterName = (LPWSTR)devNames + devNames->wDeviceOffset; printerInfo.pPortName = (LPWSTR)devNames + devNames->wOutputOffset; } PrintData *data = new PrintData(dm->engine(), &printerInfo, devMode, ranges, advanced, dm->GetRotation(), printSelection ? win->selectionOnPage : NULL); if (devNames) GlobalUnlock(pd.hDevNames); if (devMode) GlobalUnlock(pd.hDevMode); // if a file is missing and the engine can't thus be cloned, // we print using the original engine on the main thread // so that the document can't be closed and the original engine // unexpectedly deleted // TODO: instead prevent closing the document so that printing // can still happen on a separate thread and be interruptible bool failedEngineClone = dm->engine() && !data->engine; if (failedEngineClone) data->engine = dm->engine(); if (!waitForCompletion && !failedEngineClone) PrintToDeviceOnThread(win, data); else { PrintToDevice(*data); if (failedEngineClone) data->engine = NULL; delete data; } Exit: free(ppr); GlobalFree(pd.hDevNames); GlobalFree(pd.hDevMode); }