Example #1
0
void OnMenuPrint(WindowInfo *win, bool waitForCompletion) {
    // we remember some printer settings per process
    static ScopedMem<DEVMODE> defaultDevMode;
    static PrintScaleAdv defaultScaleAdv = PrintScaleShrink;

    static bool hasDefaults = false;
    if (!hasDefaults) {
        hasDefaults = true;
        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->IsDocLoaded())
        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->GetEngine()->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->GetEngine());
        return;
    }

    PRINTDLGEX pd;
    ZeroMemory(&pd, sizeof(PRINTDLGEX));
    pd.lStructSize = sizeof(PRINTDLGEX);
    pd.hwndOwner = win->hwndFrame;
    pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE;
    if (!win->currentTab->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);
    ScopedMem<DLGTEMPLATE> dlgTemplate; // needed for RTL languages
    HPROPSHEETPAGE hPsp = CreatePrintAdvancedPropSheet(&advanced, dlgTemplate);
    pd.lphPropertyPages = &hPsp;
    pd.nPropertyPages = 1;

    LPDEVNAMES devNames;
    LPDEVMODE devMode;
    bool failedEngineClone;
    PrintData *data = nullptr;

    // 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
        devMode = (LPDEVMODE)GlobalLock(pd.hDevMode);
        if (devMode) {
            defaultDevMode.Set(
                (LPDEVMODE)memdup(devMode, devMode->dmSize + devMode->dmDriverExtra));
            GlobalUnlock(pd.hDevMode);
        }
        defaultScaleAdv = advanced.scale;
    }

    if (pd.dwResultAction != PD_RESULT_PRINT)
        goto Exit;

    if (pd.Flags & PD_CURRENTPAGE) {
        PRINTPAGERANGE pr = { (DWORD)dm->CurrentPageNo(), (DWORD)dm->CurrentPageNo() };
        ranges.Append(pr);
    } else if (win->currentTab->selectionOnPage && (pd.Flags & PD_SELECTION)) {
        printSelection = true;
    } else if (!(pd.Flags & PD_PAGENUMS)) {
        PRINTPAGERANGE pr = { 1, (DWORD)dm->PageCount() };
        ranges.Append(pr);
    } else {
        assert(pd.nPageRanges > 0);
        for (DWORD i = 0; i < pd.nPageRanges; i++)
            ranges.Append(pd.lpPageRanges[i]);
    }

    devNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
    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;
    }
    data =
        new PrintData(dm->GetEngine(), &printerInfo, devMode, ranges, advanced, dm->GetRotation(),
                      printSelection ? win->currentTab->selectionOnPage : nullptr);
    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
    failedEngineClone = dm->GetEngine() && !data->engine;
    if (failedEngineClone)
        data->engine = dm->GetEngine();

    if (!waitForCompletion && !failedEngineClone)
        PrintToDeviceOnThread(win, data);
    else {
        PrintToDevice(*data);
        if (failedEngineClone)
            data->engine = nullptr;
        delete data;
    }

Exit:
    free(ppr);
    GlobalFree(pd.hDevNames);
    GlobalFree(pd.hDevMode);
}
Example #2
0
void SetMsg(const WCHAR *msg, Color color)
{
    gMsg.Set(str::Dup(msg));
    gMsgColor = color;
}
Example #3
0
static bool PrintToDevice(const PrintData &pd, ProgressUpdateUI *progressUI = nullptr,
                          AbortCookieManager *abortCookie = nullptr) {
    AssertCrash(pd.engine);
    if (!pd.engine)
        return false;
    AssertCrash(pd.printerName);
    if (!pd.printerName)
        return false;

    BaseEngine &engine = *pd.engine;
    ScopedMem<WCHAR> fileName;

    DOCINFO di = { 0 };
    di.cbSize = sizeof(DOCINFO);
    if (gPluginMode) {
        fileName.Set(url::GetFileName(gPluginURL));
        // fall back to a generic "filename" instead of the more confusing temporary filename
        di.lpszDocName = fileName ? fileName : L"filename";
    } else
        di.lpszDocName = engine.FileName();

    int current = 1, total = 0;
    if (pd.sel.Count() == 0) {
        for (size_t i = 0; i < pd.ranges.Count(); i++) {
            if (pd.ranges.At(i).nToPage < pd.ranges.At(i).nFromPage)
                total += pd.ranges.At(i).nFromPage - pd.ranges.At(i).nToPage + 1;
            else
                total += pd.ranges.At(i).nToPage - pd.ranges.At(i).nFromPage + 1;
        }
    } else {
        for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) {
            if (!BoundSelectionOnPage(pd.sel, pageNo).IsEmpty())
                total++;
        }
    }
    AssertCrash(total > 0);
    if (0 == total)
        return false;
    if (progressUI)
        progressUI->UpdateProgress(current, total);

    // cf. http://blogs.msdn.com/b/oldnewthing/archive/2012/11/09/10367057.aspx
    ScopeHDC hdc(CreateDC(nullptr, pd.printerName, nullptr, pd.devMode));
    if (!hdc)
        return false;

    if (StartDoc(hdc, &di) <= 0)
        return false;

    // MM_TEXT: Each logical unit is mapped to one device pixel.
    // Positive x is to the right; positive y is down.
    SetMapMode(hdc, MM_TEXT);

    const SizeI paperSize(GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT));
    const RectI printable(GetDeviceCaps(hdc, PHYSICALOFFSETX), GetDeviceCaps(hdc, PHYSICALOFFSETY),
                          GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES));
    const float dpiFactor = std::min(GetDeviceCaps(hdc, LOGPIXELSX) / engine.GetFileDPI(),
                                     GetDeviceCaps(hdc, LOGPIXELSY) / engine.GetFileDPI());
    bool bPrintPortrait = paperSize.dx < paperSize.dy;
    if (pd.devMode && (pd.devMode.Get()->dmFields & DM_ORIENTATION))
        bPrintPortrait = DMORIENT_PORTRAIT == pd.devMode.Get()->dmOrientation;

    if (pd.sel.Count() > 0) {
        for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) {
            RectD bounds = BoundSelectionOnPage(pd.sel, pageNo);
            if (bounds.IsEmpty())
                continue;

            if (progressUI)
                progressUI->UpdateProgress(current, total);

            StartPage(hdc);

            geomutil::SizeT<float> bSize = bounds.Size().Convert<float>();
            float zoom = std::min((float)printable.dx / bSize.dx, (float)printable.dy / bSize.dy);
            // use the correct zoom values, if the page fits otherwise
            // and the user didn't ask for anything else (default setting)
            if (PrintScaleShrink == pd.advData.scale)
                zoom = std::min(dpiFactor, zoom);
            else if (PrintScaleNone == pd.advData.scale)
                zoom = dpiFactor;

            for (size_t i = 0; i < pd.sel.Count(); i++) {
                if (pd.sel.At(i).pageNo != pageNo)
                    continue;

                RectD *clipRegion = &pd.sel.At(i).rect;
                PointI offset((int)((clipRegion->x - bounds.x) * zoom),
                              (int)((clipRegion->y - bounds.y) * zoom));
                if (pd.advData.scale != PrintScaleNone) {
                    // center the selection on the physical paper
                    offset.x += (int)(printable.dx - bSize.dx * zoom) / 2;
                    offset.y += (int)(printable.dy - bSize.dy * zoom) / 2;
                }

                bool ok = false;
                short shrink = 1;
                do {
                    RenderedBitmap *bmp = engine.RenderBitmap(
                        pd.sel.At(i).pageNo, zoom / shrink, pd.rotation, clipRegion, Target_Print,
                        abortCookie ? &abortCookie->cookie : nullptr);
                    if (abortCookie)
                        abortCookie->Clear();
                    if (bmp && bmp->GetBitmap()) {
                        RectI rc(offset.x, offset.y, bmp->Size().dx * shrink,
                                 bmp->Size().dy * shrink);
                        ok = bmp->StretchDIBits(hdc, rc);
                    }
                    delete bmp;
                    shrink *= 2;
                } while (!ok && shrink < 32 && !(progressUI && progressUI->WasCanceled()));
            }
            // TODO: abort if !ok?

            if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) {
                AbortDoc(hdc);
                return false;
            }
            current++;
        }

        EndDoc(hdc);
        return false;
    }

    // print all the pages the user requested
    for (size_t i = 0; i < pd.ranges.Count(); i++) {
        int dir = pd.ranges.At(i).nFromPage > pd.ranges.At(i).nToPage ? -1 : 1;
        for (DWORD pageNo = pd.ranges.At(i).nFromPage; pageNo != pd.ranges.At(i).nToPage + dir;
             pageNo += dir) {
            if ((PrintRangeEven == pd.advData.range && pageNo % 2 != 0) ||
                (PrintRangeOdd == pd.advData.range && pageNo % 2 == 0))
                continue;
            if (progressUI)
                progressUI->UpdateProgress(current, total);

            StartPage(hdc);

            geomutil::SizeT<float> pSize = engine.PageMediabox(pageNo).Size().Convert<float>();
            int rotation = 0;
            // Turn the document by 90 deg if it isn't in portrait mode
            if (pSize.dx > pSize.dy) {
                rotation += 90;
                std::swap(pSize.dx, pSize.dy);
            }
            // make sure not to print upside-down
            rotation = (rotation % 180) == 0 ? 0 : 270;
            // finally turn the page by (another) 90 deg in landscape mode
            if (!bPrintPortrait) {
                rotation = (rotation + 90) % 360;
                std::swap(pSize.dx, pSize.dy);
            }

            // dpiFactor means no physical zoom
            float zoom = dpiFactor;
            // offset of the top-left corner of the page from the printable area
            // (negative values move the page into the left/top margins, etc.);
            // offset adjustments are needed because the GDI coordinate system
            // starts at the corner of the printable area and we rather want to
            // center the page on the physical paper (except for PrintScaleNone
            // where the page starts at the very top left of the physical paper so
            // that printing forms/labels of varying size remains reliably possible)
            PointI offset(printable.x, printable.y);

            if (pd.advData.scale != PrintScaleNone) {
                // make sure to fit all content into the printable area when scaling
                // and the whole document page on the physical paper
                RectD rect = engine.PageContentBox(pageNo, Target_Print);
                geomutil::RectT<float> cbox =
                    engine.Transform(rect, pageNo, 1.0, rotation).Convert<float>();
                zoom = std::min((float)printable.dx / cbox.dx,
                                std::min((float)printable.dy / cbox.dy,
                                         std::min((float)paperSize.dx / pSize.dx,
                                                  (float)paperSize.dy / pSize.dy)));
                // use the correct zoom values, if the page fits otherwise
                // and the user didn't ask for anything else (default setting)
                if (PrintScaleShrink == pd.advData.scale && dpiFactor < zoom)
                    zoom = dpiFactor;
                // center the page on the physical paper
                offset.x += (int)(paperSize.dx - pSize.dx * zoom) / 2;
                offset.y += (int)(paperSize.dy - pSize.dy * zoom) / 2;
                // make sure that no content lies in the non-printable paper margins
                geomutil::RectT<float> onPaper(printable.x + offset.x + cbox.x * zoom,
                                               printable.y + offset.y + cbox.y * zoom,
                                               cbox.dx * zoom, cbox.dy * zoom);
                if (onPaper.x < printable.x)
                    offset.x += (int)(printable.x - onPaper.x);
                else if (onPaper.BR().x > printable.BR().x)
                    offset.x -= (int)(onPaper.BR().x - printable.BR().x);
                if (onPaper.y < printable.y)
                    offset.y += (int)(printable.y - onPaper.y);
                else if (onPaper.BR().y > printable.BR().y)
                    offset.y -= (int)(onPaper.BR().y - printable.BR().y);
            }

            bool ok = false;
            short shrink = 1;
            do {
                RenderedBitmap *bmp =
                    engine.RenderBitmap(pageNo, zoom / shrink, rotation, nullptr, Target_Print,
                                        abortCookie ? &abortCookie->cookie : nullptr);
                if (abortCookie)
                    abortCookie->Clear();
                if (bmp && bmp->GetBitmap()) {
                    RectI rc(offset.x, offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink);
                    ok = bmp->StretchDIBits(hdc, rc);
                }
                delete bmp;
                shrink *= 2;
            } while (!ok && shrink < 32 && !(progressUI && progressUI->WasCanceled()));
            // TODO: abort if !ok?

            if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) {
                AbortDoc(hdc);
                return false;
            }
            current++;
        }
    }

    EndDoc(hdc);
    return true;
}
Example #4
0
static void SerializeAdvancedSettings(const WCHAR *filepath, SettingInfo *info, size_t count, void *structBase)
{
    char *base = (char *)structBase;
    const WCHAR *section = NULL;
    bool skipSection = false;
    ScopedMem<WCHAR> strValue;

    for (size_t i = 0; i < count; i++) {
        SettingInfo& meta = info[i];
        CrashIf(meta.type != SType_Section && !section);
        if (meta.type != SType_Section && skipSection)
            continue;
        switch (meta.type) {
        case SType_Section:
            section = meta.name;
            skipSection = !meta.offset;
            break;
        case SType_Bool:
            strValue.Set(str::Format(L"%d", *(bool *)(base + meta.offset) ? 1 : 0));
            WritePrivateProfileString(section, meta.name, strValue, filepath);
            break;
        case SType_Color:
            strValue.Set(str::Format(L"#%06X", (int)*(COLORREF *)(base + meta.offset)));
            WritePrivateProfileString(section, meta.name, strValue, filepath);
            break;
        case SType_Int:
            strValue.Set(str::Format(L"%d", *(int *)(base + meta.offset)));
            WritePrivateProfileString(section, meta.name, strValue, filepath);
            break;
        case SType_String:
            WritePrivateProfileString(section, meta.name, ((ScopedMem<WCHAR> *)(base + meta.offset))->Get(), filepath);
            break;
        case SType_BoolVec:
            {
                Vec<bool> *vec = (Vec<bool> *)(base + meta.offset);
                for (size_t n = 1; n < vec->Count(); n++) {
                    ScopedMem<WCHAR> key(str::Format(L"%u.%s", n, meta.name));
                    strValue.Set(str::Format(L"%d", vec->At(n) ? 1 : 0));
                    WritePrivateProfileString(section, key, strValue, filepath);
                }
            }
            break;
        case SType_ColorVec:
            {
                Vec<COLORREF> *vec = (Vec<COLORREF> *)(base + meta.offset);
                for (size_t n = 1; n < vec->Count(); n++) {
                    ScopedMem<WCHAR> key(str::Format(L"%u.%s", n, meta.name));
                    strValue.Set(str::Format(L"#%06X", (int)vec->At(n)));
                    WritePrivateProfileString(section, key, strValue, filepath);
                }
            }
            break;
        case SType_IntVec:
            {
                Vec<int> *vec = (Vec<int> *)(base + meta.offset);
                for (size_t n = 1; n < vec->Count(); n++) {
                    ScopedMem<WCHAR> key(str::Format(L"%u.%s", n, meta.name));
                    strValue.Set(str::Format(L"%d", vec->At(n)));
                    WritePrivateProfileString(section, key, strValue, filepath);
                }
            }
            break;
        case SType_StringVec:
            {
                WStrVec *vec = (WStrVec *)(base + meta.offset);
                for (size_t n = 1; n < vec->Count(); n++) {
                    ScopedMem<WCHAR> key(str::Format(L"%u.%s", n, meta.name));
                    WritePrivateProfileString(section, key, vec->At(n), filepath);
                }
            }
            break;
        }
    }
}
Example #5
0
// returns true if the double-click was handled and false if it wasn't
bool OnInverseSearch(WindowInfo *win, int x, int y)
{
    if (!HasPermission(Perm_DiskAccess) || gPluginMode) return false;
    if (!win->IsDocLoaded() || win->dm->engineType != Engine_PDF) return false;

    // Clear the last forward-search result
    win->fwdSearchMark.rects.Reset();
    InvalidateRect(win->hwndCanvas, NULL, FALSE);

    // On double-clicking error message will be shown to the user
    // if the PDF does not have a synchronization file
    if (!win->pdfsync) {
        int err = Synchronizer::Create(win->loadedFilePath,
            static_cast<PdfEngine *>(win->dm->engine), &win->pdfsync);
        if (err == PDFSYNCERR_SYNCFILE_NOTFOUND) {
            // We used to warn that "No synchronization file found" at this
            // point if gGlobalPrefs.enableTeXEnhancements is set; we no longer
            // so do because a double-click has several other meanings
            // (selecting a word or an image, navigating quickly using links)
            // and showing an unrelated warning in all those cases seems wrong
            return false;
        }
        if (err != PDFSYNCERR_SUCCESS) {
            ShowNotification(win, _TR("Synchronization file cannot be opened"));
            return true;
        }
        gGlobalPrefs.enableTeXEnhancements = true;
    }

    int pageNo = win->dm->GetPageNoByPoint(PointI(x, y));
    if (!win->dm->ValidPageNo(pageNo))
        return false;

    PointI pt = win->dm->CvtFromScreen(PointI(x, y), pageNo).Convert<int>();
    ScopedMem<WCHAR> srcfilepath;
    UINT line, col;
    int err = win->pdfsync->DocToSource(pageNo, pt, srcfilepath, &line, &col);
    if (err != PDFSYNCERR_SUCCESS) {
        ShowNotification(win, _TR("No synchronization info at this position"));
        return true;
    }

    WCHAR *inverseSearch = gGlobalPrefs.inverseSearchCmdLine;
    if (!inverseSearch)
        // Detect a text editor and use it as the default inverse search handler for now
        inverseSearch = AutoDetectInverseSearchCommands();

    ScopedMem<WCHAR> cmdline;
    if (inverseSearch)
        cmdline.Set(win->pdfsync->PrepareCommandline(inverseSearch, srcfilepath, line, col));
    if (!str::IsEmpty(cmdline.Get())) {
        // resolve relative paths with relation to SumatraPDF.exe's directory
        ScopedMem<WCHAR> appDir(GetExePath());
        if (appDir)
            appDir.Set(path::GetDir(appDir));
        ScopedHandle process(LaunchProcess(cmdline, appDir));
        if (!process)
            ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings."));
    }
    else if (gGlobalPrefs.enableTeXEnhancements)
        ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings."));

    if (inverseSearch != gGlobalPrefs.inverseSearchCmdLine)
        free(inverseSearch);

    return true;
}
Example #6
0
void DumpProperties(BaseEngine *engine, bool fullDump)
{
    Out("\t<Properties\n");
    ScopedMem<char> str;
    str.Set(Escape(str::Dup(engine->FileName())));
    Out("\t\tFilePath=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_Title)));
    if (str)
        Out("\t\tTitle=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_Subject)));
    if (str)
        Out("\t\tSubject=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_Author)));
    if (str)
        Out("\t\tAuthor=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_Copyright)));
    if (str)
        Out("\t\tCopyright=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_CreationDate)));
    if (str)
        Out("\t\tCreationDate=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_ModificationDate)));
    if (str)
        Out("\t\tModDate=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_CreatorApp)));
    if (str)
        Out("\t\tCreator=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_PdfProducer)));
    if (str)
        Out("\t\tPdfProducer=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_PdfVersion)));
    if (str)
        Out("\t\tPdfVersion=\"%s\"\n", str.Get());
    str.Set(Escape(engine->GetProperty(Prop_PdfFileStructure)));
    if (str)
        Out("\t\tPdfFileStructure=\"%s\"\n", str.Get());
    if (!engine->AllowsPrinting())
        Out("\t\tPrintingAllowed=\"no\"\n");
    if (!engine->AllowsCopyingText())
        Out("\t\tCopyingTextAllowed=\"no\"\n");
    if (engine->IsImageCollection())
        Out("\t\tImageCollection=\"yes\"\n");
    if (engine->PreferredLayout())
        Out("\t\tPreferredLayout=\"%d\"\n", engine->PreferredLayout());
    Out("\t/>\n");

    if (fullDump) {
        ScopedMem<WCHAR> fontlist(engine->GetProperty(Prop_FontList));
        if (fontlist) {
            WStrVec fonts;
            fonts.Split(fontlist, L"\n");
            str.Set(Escape(fonts.Join(L"\n\t\t")));
            Out("\t<FontList>\n\t\t%s\n\t</FontList>\n", str.Get());
        }
    }
}
Example #7
0
HRESULT CPdfFilter::GetNextChunkValue(CChunkValue &chunkValue)
{
    ScopedMem<TCHAR> str;

    switch (m_state) {
    case STATE_PDF_START:
        m_state = STATE_PDF_AUTHOR;
        chunkValue.SetTextValue(PKEY_PerceivedType, L"document");
        return S_OK;

    case STATE_PDF_AUTHOR:
        m_state = STATE_PDF_TITLE;
        str.Set(m_pdfEngine->GetProperty(Prop_Author));
        if (!str::IsEmpty(str.Get())) {
            chunkValue.SetTextValue(PKEY_Author, AsWStrQ(str));
            return S_OK;
        }
        // fall through

    case STATE_PDF_TITLE:
        m_state = STATE_PDF_DATE;
        str.Set(m_pdfEngine->GetProperty(Prop_Title));
        if (!str) str.Set(m_pdfEngine->GetProperty(Prop_Subject));
        if (!str::IsEmpty(str.Get())) {
            chunkValue.SetTextValue(PKEY_Title, AsWStrQ(str));
            return S_OK;
        }
        // fall through

    case STATE_PDF_DATE:
        m_state = STATE_PDF_CONTENT;
        str.Set(m_pdfEngine->GetProperty(Prop_ModificationDate));
        if (!str) str.Set(m_pdfEngine->GetProperty(Prop_CreationDate));
        if (!str::IsEmpty(str.Get())) {
            SYSTEMTIME systime;
            if (PdfDateParse(str, &systime)) {
                FILETIME filetime;
                SystemTimeToFileTime(&systime, &filetime);
                chunkValue.SetFileTimeValue(PKEY_ItemDate, filetime);
                return S_OK;
            }
        }
        // fall through

    case STATE_PDF_CONTENT:
        while (++m_iPageNo <= m_pdfEngine->PageCount()) {
            str.Set(m_pdfEngine->ExtractPageText(m_iPageNo, _T("\r\n")));
            if (str::IsEmpty(str.Get()))
                continue;
            chunkValue.SetTextValue(PKEY_Search_Contents, AsWStrQ(str), CHUNK_TEXT);
            return S_OK;
        }
        m_state = STATE_PDF_END;
        // fall through

    case STATE_PDF_END:
    default:
        return FILTER_E_END_OF_CHUNKS;
    }
}
Example #8
0
void SetAppDataPath(const WCHAR *path)
{
    gAppDataPath.Set(path::Normalize(path));
}
Example #9
0
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 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);
}
Example #10
0
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    int retCode = 1;    // by default it's error

#ifdef DEBUG
    // Memory leak detection (only enable _CRTDBG_LEAK_CHECK_DF for
    // regular termination so that leaks aren't checked on exceptions,
    // aborts, etc. where some clean-up might not take place)
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF);
    //_CrtSetBreakAlloc(421);
    TryLoadMemTrace();
#endif


    DisableDataExecution();
    // ensure that C functions behave consistently under all OS locales
    // (use Win32 functions where localized input or output is desired)
    setlocale(LC_ALL, "C");
    // don't show system-provided dialog boxes when accessing files on drives
    // that are not mounted (e.g. a: drive without floppy or cd rom drive
    // without a cd).
    SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);

#if defined(DEBUG) || defined(SVN_PRE_RELEASE_VER)
    if (str::StartsWith(lpCmdLine, "/tester")) {
        extern int TesterMain(); // in Tester.cpp
        return TesterMain();
    }

    if (str::StartsWith(lpCmdLine, "/regress")) {
        extern int RegressMain(); // in Regress.cpp
        return RegressMain();
    }
#endif

    RunUnitTests();

    srand((unsigned int)time(NULL));

    // don't bother sending crash reports when running under Wine
    // as they're not helpful
    if (!RunningUnderWine()) {
        ScopedMem<WCHAR> symDir;
        ScopedMem<WCHAR> tmpDir(path::GetTempPath());
        if (tmpDir)
            symDir.Set(path::Join(tmpDir, L"SumatraPDF-symbols"));
        else
            symDir.Set(AppGenDataFilename(L"SumatraPDF-symbols"));
        ScopedMem<WCHAR> crashDumpPath(AppGenDataFilename(CRASH_DUMP_FILE_NAME));
        InstallCrashHandler(crashDumpPath, symDir);
    }

    ScopedOle ole;
    InitAllCommonControls();
    ScopedGdiPlus gdiPlus(true);
    mui::Initialize();
    uitask::Initialize();

    ScopedMem<WCHAR> prefsFilename(GetPrefsFileName());
    if (!file::Exists(prefsFilename)) {
        // guess the ui language on first start
        CurrLangNameSet(trans::GuessLanguage());
        gFavorites = new Favorites();
    } else {
        assert(gFavorites == NULL);
        Prefs::Load(prefsFilename, gGlobalPrefs, gFileHistory, &gFavorites);
        CurrLangNameSet(gGlobalPrefs.currentLanguage);
    }
    prefsFilename.Set(NULL);

    CommandLineInfo i;
    GetCommandLineInfo(i);

    if (i.showConsole)
        RedirectIOToConsole();
    if (i.makeDefault)
        AssociateExeWithPdfExtension();
    if (i.pathsToBenchmark.Count() > 0) {
        BenchFileOrDir(i.pathsToBenchmark);
        if (i.showConsole)
            system("pause");
    }
    if (i.exitImmediately)
        goto Exit;
    gCrashOnOpen = i.crashOnOpen;

    gGlobalPrefs.bgColor = i.bgColor;
    gGlobalPrefs.fwdSearch.offset = i.fwdSearch.offset;
    gGlobalPrefs.fwdSearch.width = i.fwdSearch.width;
    gGlobalPrefs.fwdSearch.color = i.fwdSearch.color;
    gGlobalPrefs.fwdSearch.permanent = i.fwdSearch.permanent;
    gGlobalPrefs.escToExit = i.escToExit;
    gGlobalPrefs.cbxR2L = i.cbxR2L;
    gPolicyRestrictions = GetPolicies(i.restrictedUse);
    gRenderCache.colorRange[0] = i.colorRange[0];
    gRenderCache.colorRange[1] = i.colorRange[1];
    DebugGdiPlusDevice(gUseGdiRenderer);
    DebugAlternateChmEngine(!gUseEbookUI);

    if (i.inverseSearchCmdLine) {
        str::ReplacePtr(&gGlobalPrefs.inverseSearchCmdLine, i.inverseSearchCmdLine);
        gGlobalPrefs.enableTeXEnhancements = true;
    }
    CurrLangNameSet(i.lang);

    if (!RegisterWinClass(hInstance))
        goto Exit;
    if (!InstanceInit(hInstance, nCmdShow))
        goto Exit;

    if (i.hwndPluginParent) {
        if (!SetupPluginMode(i))
            goto Exit;
    }

    if (i.printerName) {
        // note: this prints all PDF files. Another option would be to
        // print only the first one
        for (size_t n = 0; n < i.fileNames.Count(); n++) {
            bool ok = PrintFile(i.fileNames.At(n), i.printerName, !i.silent, i.printSettings);
            if (!ok)
                retCode++;
        }
        --retCode; // was 1 if no print failures, turn 1 into 0
        goto Exit;
    }

    if (i.fileNames.Count() == 0 && gGlobalPrefs.rememberOpenedFiles && gGlobalPrefs.showStartPage) {
        // make the shell prepare the image list, so that it's ready when the first window's loaded
        SHFILEINFO sfi;
        SHGetFileInfo(L".pdf", 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
    }

    WindowInfo *win = NULL;
    bool isFirstWin = true;

    for (size_t n = 0; n < i.fileNames.Count(); n++) {
        if (i.reuseInstance && !i.printDialog) {
            OpenUsingDde(i.fileNames.At(n), i, isFirstWin);
        } else {
            win = LoadOnStartup(i.fileNames.At(n), i, isFirstWin);
            if (!win) {
                retCode++;
                continue;
            }
            if (i.printDialog)
                OnMenuPrint(win, i.exitOnPrint);
        }
        isFirstWin = false;
    }
    if (i.fileNames.Count() > 0 && isFirstWin) {
        // failed to create any window, even though there
        // were files to load (or show a failure message for)
        goto Exit;
    }

    if (i.reuseInstance && !i.printDialog || i.printDialog && i.exitOnPrint)
        goto Exit;

    if (isFirstWin) {
        win = CreateAndShowWindowInfo();
        if (!win)
            goto Exit;
    }

    UpdateUITextForLanguage(); // needed for RTL languages
    if (isFirstWin)
        UpdateToolbarAndScrollbarState(*win);

    // Make sure that we're still registered as default,
    // if the user has explicitly told us to be
    if (gGlobalPrefs.pdfAssociateShouldAssociate && win)
        RegisterForPdfExtentions(win->hwndFrame);

    if (gGlobalPrefs.enableAutoUpdate && gWindows.Count() > 0)
        AutoUpdateCheckAsync(gWindows.At(0)->hwndFrame, true);

    if (i.stressTestPath)
        StartStressTest(&i, win, &gRenderCache);

    retCode = RunMessageLoop();

    CleanUpThumbnailCache(gFileHistory);

Exit:
    while (gWindows.Count() > 0) {
        DeleteWindowInfo(gWindows.At(0));
    }
    while (gEbookWindows.Count() > 0) {
        DeleteEbookWindow(gEbookWindows.At(0), true);
    }

#ifndef DEBUG
    // leave all the remaining clean-up to the OS
    // (as recommended for a quick exit)
    ExitProcess(retCode);
#endif

    DeleteObject(gBrushNoDocBg);
    DeleteObject(gBrushLogoBg);
    DeleteObject(gBrushAboutBg);
    DeleteObject(gDefaultGuiFont);
    DeleteBitmap(gBitmapReloadingCue);

    delete gFavorites;

    mui::Destroy();
    uitask::Destroy();

    trans::Destroy();

    // it's still possible to crash after this (destructors of static classes,
    // atexit() code etc.) point, but it's very unlikely
    UninstallCrashHandler();

#ifdef DEBUG
    // output leaks after all destructors of static objects have run
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

    return retCode;
}
Example #11
0
void SelectTranslation(const WCHAR *exePath=NULL)
{
    LANGID langId = GetUserDefaultUILanguage();
    int idx = GetLanguageIndex(langId);
    if (-1 == idx) {
        // try a neutral language if the specific sublanguage isn't available
        langId = MAKELANGID(PRIMARYLANGID(langId), SUBLANG_NEUTRAL);
        idx = GetLanguageIndex(langId);
    }
    if (-1 != idx) {
        gTranslationIdx = idx;
        plogf("sp: Detected language %s (%d)", gLanguages[idx / gTranslationsCount], idx);
    }

    // try to extract the language used by SumatraPDF
    ScopedMem<WCHAR> path;
    if (exePath) {
        path.Set(path::GetDir(exePath));
        path.Set(path::Join(path, PREFS_FILE_NAME));
    }
    if (!file::Exists(path)) {
        path.Set(GetSpecialFolder(CSIDL_APPDATA));
        path.Set(path::Join(path, L"SumatraPDF\\" PREFS_FILE_NAME));
    }
    if (!file::Exists(path))
        return;
    plogf("sp: Found preferences at %S", path);
#ifndef USE_INI_SETTINGS
    ScopedMem<char> data(file::ReadAll(path, NULL));
    if (data) {
        BencObj *root = BencObj::Decode(data);
        if (root && root->Type() == BT_DICT) {
            BencDict *global = static_cast<BencDict *>(root)->GetDict("gp");
            BencString *string = global ? global->GetString("UILanguage") : NULL;
            if (string) {
                plogf("sp: UILanguage from preferences: %s", string->RawValue());
                for (int i = 0; gLanguages[i]; i++) {
                    if (str::Eq(gLanguages[i], string->RawValue())) {
                        gTranslationIdx = i * gTranslationsCount;
                        break;
                    }
                }
            }
        }
        delete root;
    }
#else
    IniFile ini(path);
    IniSection *section = ini.FindSection(NULL);
    IniLine *line = section ? section->FindLine("CurrLangCode") : NULL;
    if (line) {
        plogf("sp: UILanguage from preferences: %s", line->value);
        for (int i = 0; gLanguages[i]; i++) {
            if (str::Eq(gLanguages[i], line->value)) {
                gTranslationIdx = i * gTranslationsCount;
                break;
            }
        }
    }
#endif
}
Example #12
0
static bool PrintToDevice(PrintData& pd, ProgressUpdateUI *progressUI=NULL, AbortCookieManager *abortCookie=NULL)
{
    AssertCrash(pd.engine);
    if (!pd.engine)
        return false;
    AssertCrash(pd.printerName);
    if (!pd.printerName)
        return false;

    BaseEngine& engine = *pd.engine;
    ScopedMem<WCHAR> fileName;

    DOCINFO di = { 0 };
    di.cbSize = sizeof (DOCINFO);
    if (gPluginMode) {
        fileName.Set(ExtractFilenameFromURL(gPluginURL));
        // fall back to a generic "filename" instead of the more confusing temporary filename
        di.lpszDocName = fileName ? fileName : L"filename";
    }
    else
        di.lpszDocName = engine.FileName();

    int current = 1, total = 0;
    if (pd.sel.Count() == 0) {
        for (size_t i = 0; i < pd.ranges.Count(); i++) {
            if (pd.ranges.At(i).nToPage < pd.ranges.At(i).nFromPage)
                total += pd.ranges.At(i).nFromPage - pd.ranges.At(i).nToPage + 1;
            else
                total += pd.ranges.At(i).nToPage - pd.ranges.At(i).nFromPage + 1;
        }
    }
    else {
        for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) {
            if (!BoundSelectionOnPage(pd.sel, pageNo).IsEmpty())
                total++;
        }
    }
    AssertCrash(total > 0);
    if (0 == total)
        return false;
    if (progressUI)
        progressUI->UpdateProgress(current, total);

    // cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1882
    // According to our crash dumps, Cannon printer drivers (caprenn.dll etc.)
    // are buggy and like to crash during printing with DEP violation
    // We disable dep during printing to hopefully not crash
    // TODO: even better would be to print in a separate process so that
    // crashes during printing wouldn't affect the main process. It's also
    // much more complicated to implement
    ScopeDisableDEP scopeNoDEP;

    // cf. http://blogs.msdn.com/b/oldnewthing/archive/2012/11/09/10367057.aspx
    ScopeHDC hdc(CreateDC(pd.driverName, pd.printerName, pd.portName, pd.devMode));
    if (!hdc)
        return false;

    if (StartDoc(hdc, &di) <= 0)
        return false;

    // MM_TEXT: Each logical unit is mapped to one device pixel.
    // Positive x is to the right; positive y is down.
    SetMapMode(hdc, MM_TEXT);

    const SizeI paperSize(GetDeviceCaps(hdc, PHYSICALWIDTH),
                          GetDeviceCaps(hdc, PHYSICALHEIGHT));
    const RectI printable(GetDeviceCaps(hdc, PHYSICALOFFSETX),
                          GetDeviceCaps(hdc, PHYSICALOFFSETY),
                          GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES));
    const float dpiFactor = min(GetDeviceCaps(hdc, LOGPIXELSX) / engine.GetFileDPI(),
                                GetDeviceCaps(hdc, LOGPIXELSY) / engine.GetFileDPI());
    bool bPrintPortrait = paperSize.dx < paperSize.dy;
    if (pd.devMode && (pd.devMode.Get()->dmFields & DM_ORIENTATION))
        bPrintPortrait = DMORIENT_PORTRAIT == pd.devMode.Get()->dmOrientation;

    if (pd.sel.Count() > 0) {
        for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) {
            RectD bounds = BoundSelectionOnPage(pd.sel, pageNo);
            if (bounds.IsEmpty())
                continue;

            if (progressUI)
                progressUI->UpdateProgress(current, total);

            StartPage(hdc);

            SizeT<float> bSize = bounds.Size().Convert<float>();
            float zoom = min((float)printable.dx / bSize.dx,
                             (float)printable.dy / bSize.dy);
            // use the correct zoom values, if the page fits otherwise
            // and the user didn't ask for anything else (default setting)
            if (PrintScaleShrink == pd.advData.scale)
                zoom = min(dpiFactor, zoom);
            else if (PrintScaleNone == pd.advData.scale)
                zoom = dpiFactor;

            for (size_t i = 0; i < pd.sel.Count(); i++) {
                if (pd.sel.At(i).pageNo != pageNo)
                    continue;

                RectD *clipRegion = &pd.sel.At(i).rect;
                PointI offset((int)((clipRegion->x - bounds.x) * zoom), (int)((clipRegion->y - bounds.y) * zoom));
                if (!pd.advData.asImage) {
                    RectI rc((int)(printable.dx - bSize.dx * zoom) / 2 + offset.x,
                             (int)(printable.dy - bSize.dy * zoom) / 2 + offset.y,
                             (int)(clipRegion->dx * zoom), (int)(clipRegion->dy * zoom));
                    engine.RenderPage(hdc, rc, pd.sel.At(i).pageNo, zoom, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : NULL);
                    if (abortCookie)
                        abortCookie->Clear();
                }
                else {
                    RenderedBitmap *bmp = NULL;
                    short shrink = 1;
                    do {
                        bmp = engine.RenderBitmap(pd.sel.At(i).pageNo, zoom / shrink, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : NULL);
                        if (abortCookie)
                            abortCookie->Clear();
                        if (!bmp || !bmp->GetBitmap()) {
                            shrink *= 2;
                            delete bmp;
                            bmp = NULL;
                        }
                    } while (!bmp && shrink < 32 && !(progressUI && progressUI->WasCanceled()));
                    if (bmp) {
                        RectI rc((int)(paperSize.dx - bSize.dx * zoom) / 2 + offset.x,
                                 (int)(paperSize.dy - bSize.dy * zoom) / 2 + offset.y,
                                 bmp->Size().dx * shrink, bmp->Size().dy * shrink);
                        bmp->StretchDIBits(hdc, rc);
                        delete bmp;
                    }
                }
            }

            if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) {
                AbortDoc(hdc);
                return false;
            }
            current++;
        }

        EndDoc(hdc);
        return false;
    }

    // print all the pages the user requested
    for (size_t i = 0; i < pd.ranges.Count(); i++) {
        int dir = pd.ranges.At(i).nFromPage > pd.ranges.At(i).nToPage ? -1 : 1;
        for (DWORD pageNo = pd.ranges.At(i).nFromPage; pageNo != pd.ranges.At(i).nToPage + dir; pageNo += dir) {
            if ((PrintRangeEven == pd.advData.range && pageNo % 2 != 0) ||
                (PrintRangeOdd == pd.advData.range && pageNo % 2 == 0))
                continue;
            if (progressUI)
                progressUI->UpdateProgress(current, total);

            StartPage(hdc);

            SizeT<float> pSize = engine.PageMediabox(pageNo).Size().Convert<float>();
            int rotation = 0;
            // Turn the document by 90 deg if it isn't in portrait mode
            if (pSize.dx > pSize.dy) {
                rotation += 90;
                swap(pSize.dx, pSize.dy);
            }
            // make sure not to print upside-down
            rotation = (rotation % 180) == 0 ? 0 : 270;
            // finally turn the page by (another) 90 deg in landscape mode
            if (!bPrintPortrait) {
                rotation = (rotation + 90) % 360;
                swap(pSize.dx, pSize.dy);
            }

            // dpiFactor means no physical zoom
            float zoom = dpiFactor;
            // offset of the top-left corner of the page from the printable area
            // (negative values move the page into the left/top margins, etc.);
            // offset adjustments are needed because the GDI coordinate system
            // starts at the corner of the printable area and we rather want to
            // center the page on the physical paper (default behavior)
            PointI offset(-printable.x, -printable.y);

            if (pd.advData.scale != PrintScaleNone) {
                // make sure to fit all content into the printable area when scaling
                // and the whole document page on the physical paper
                RectD rect = engine.PageContentBox(pageNo, Target_Print);
                RectT<float> cbox = engine.Transform(rect, pageNo, 1.0, rotation).Convert<float>();
                zoom = min((float)printable.dx / cbox.dx,
                       min((float)printable.dy / cbox.dy,
                       min((float)paperSize.dx / pSize.dx,
                           (float)paperSize.dy / pSize.dy)));
                // use the correct zoom values, if the page fits otherwise
                // and the user didn't ask for anything else (default setting)
                if (PrintScaleShrink == pd.advData.scale && dpiFactor < zoom)
                    zoom = dpiFactor;
                // make sure that no content lies in the non-printable paper margins
                RectT<float> onPaper((paperSize.dx - pSize.dx * zoom) / 2 + cbox.x * zoom,
                                     (paperSize.dy - pSize.dy * zoom) / 2 + cbox.y * zoom,
                                     cbox.dx * zoom, cbox.dy * zoom);
                if (onPaper.x < printable.x)
                    offset.x += (int)(printable.x - onPaper.x);
                else if (onPaper.BR().x > printable.BR().x)
                    offset.x -= (int)(onPaper.BR().x - printable.BR().x);
                if (onPaper.y < printable.y)
                    offset.y += (int)(printable.y - onPaper.y);
                else if (onPaper.BR().y > printable.BR().y)
                    offset.y -= (int)(onPaper.BR().y - printable.BR().y);
            }

            if (!pd.advData.asImage) {
                RectI rc = RectI::FromXY((int)(paperSize.dx - pSize.dx * zoom) / 2 + offset.x,
                                         (int)(paperSize.dy - pSize.dy * zoom) / 2 + offset.y,
                                         paperSize.dx, paperSize.dy);
                engine.RenderPage(hdc, rc, pageNo, zoom, rotation, NULL, Target_Print, abortCookie ? &abortCookie->cookie : NULL);
                if (abortCookie)
                    abortCookie->Clear();
            }
            else {
                RenderedBitmap *bmp = NULL;
                short shrink = 1;
                do {
                    bmp = engine.RenderBitmap(pageNo, zoom / shrink, rotation, NULL, Target_Print, abortCookie ? &abortCookie->cookie : NULL);
                    if (abortCookie)
                        abortCookie->Clear();
                    if (!bmp || !bmp->GetBitmap()) {
                        shrink *= 2;
                        delete bmp;
                        bmp = NULL;
                    }
                } while (!bmp && shrink < 32 && !(progressUI && progressUI->WasCanceled()));
                if (bmp) {
                    RectI rc((paperSize.dx - bmp->Size().dx * shrink) / 2 + offset.x,
                             (paperSize.dy - bmp->Size().dy * shrink) / 2 + offset.y,
                             bmp->Size().dx * shrink, bmp->Size().dy * shrink);
                    bmp->StretchDIBits(hdc, rc);
                    delete bmp;
                }
            }

            if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) {
                AbortDoc(hdc);
                return false;
            }
            current++;
        }
    }

    EndDoc(hdc);
    return true;
}
Example #13
0
int main(int argc, char **argv)
{
    setlocale(LC_ALL, "C");
    DisableDataExecution();

    WStrVec argList;
    ParseCmdLine(GetCommandLine(), argList);
    if (argList.Count() < 2) {
Usage:
        ErrOut("%s [-pwd <password>][-quick][-render <path-%%d.tga>] <filename>",
            path::GetBaseName(argList.At(0)));
        return 2;
    }

    ScopedMem<WCHAR> filePath;
    WCHAR *password = NULL;
    bool fullDump = true;
    WCHAR *renderPath = NULL;
    float renderZoom = 1.f;
    bool useAlternateHandlers = false;
    bool loadOnly = false, silent = false;
#ifdef DEBUG
    int breakAlloc = 0;
#endif

    for (size_t i = 1; i < argList.Count(); i++) {
        if (str::Eq(argList.At(i), L"-pwd") && i + 1 < argList.Count() && !password)
            password = argList.At(++i);
        else if (str::Eq(argList.At(i), L"-quick"))
            fullDump = false;
        else if (str::Eq(argList.At(i), L"-render") && i + 1 < argList.Count() && !renderPath) {
            // optional zoom argument (e.g. -render 50% file.pdf)
            float zoom;
            if (i + 2 < argList.Count() && str::Parse(argList.At(i + 1), L"%f%%%$", &zoom) && zoom > 0.f) {
                renderZoom = zoom / 100.f;
                i++;
            }
            renderPath = argList.At(++i);
        }
        // -alt is for debugging alternate rendering methods
        else if (str::Eq(argList.At(i), L"-alt"))
            useAlternateHandlers = true;
        // -loadonly and -silent are only meant for profiling
        else if (str::Eq(argList.At(i), L"-loadonly"))
            loadOnly = true;
        else if (str::Eq(argList.At(i), L"-silent"))
            silent = true;
        // -full is for backward compatibility
        else if (str::Eq(argList.At(i), L"-full"))
            fullDump = true;
#ifdef DEBUG
        else if (str::Eq(argList.At(i), L"-breakalloc") && i + 1 < argList.Count())
            breakAlloc = _wtoi(argList.At(++i));
#endif
        else if (!filePath)
            filePath.Set(str::Dup(argList.At(i)));
        else
            goto Usage;
    }
    if (!filePath)
        goto Usage;

#ifdef DEBUG
    if (breakAlloc) {
        _CrtSetBreakAlloc(breakAlloc);
        if (!IsDebuggerPresent())
            MessageBox(NULL, L"Keep your debugger ready for the allocation breakpoint...", L"EngineDump", MB_ICONINFORMATION);
    }
#endif
    if (silent) {
        FILE *nul;
        freopen_s(&nul, "NUL", "w", stdout);
        freopen_s(&nul, "NUL", "w", stderr);
    }

    // optionally use GDI+ rendering for PDF/XPS
    DebugGdiPlusDevice(useAlternateHandlers);

    ScopedGdiPlus gdiPlus;
    ScopedMiniMui miniMui;

    WIN32_FIND_DATA fdata;
    HANDLE hfind = FindFirstFile(filePath, &fdata);
    // embedded documents are referred to by an invalid path
    // containing more information after a colon (e.g. "C:\file.pdf:3:0")
    if (INVALID_HANDLE_VALUE != hfind) {
        ScopedMem<WCHAR> dir(path::GetDir(filePath));
        filePath.Set(path::Join(dir, fdata.cFileName));
        FindClose(hfind);
    }

    EngineType engineType;
    PasswordHolder pwdUI(password);
    BaseEngine *engine = EngineManager::CreateEngine(filePath, &pwdUI, &engineType);
    if (!engine) {
        ErrOut("Error: Couldn't create an engine for %s!", path::GetBaseName(filePath));
        return 1;
    }
    Vec<PageAnnotation> *userAnnots = LoadFileModifications(engine->FileName());
    engine->UpdateUserAnnotations(userAnnots);
    delete userAnnots;
    if (!loadOnly)
        DumpData(engine, fullDump);
    if (renderPath)
        RenderDocument(engine, renderPath, renderZoom, silent);
    delete engine;

#ifdef DEBUG
    // report memory leaks on stderr for engines that shouldn't leak
    if (engineType != Engine_DjVu) {
        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    }
#endif

    return 0;
}
Example #14
0
int SyncTex::SourceToDoc(const WCHAR* srcfilename, UINT line, UINT col, UINT *page, Vec<RectI> &rects)
{
    if (IsIndexDiscarded())
        if (RebuildIndex() != PDFSYNCERR_SUCCESS)
            return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;
    assert(this->scanner);

    ScopedMem<WCHAR> srcfilepath;
    // convert the source file to an absolute path
    if (PathIsRelative(srcfilename))
        srcfilepath.Set(PrependDir(srcfilename));
    else
        srcfilepath.Set(str::Dup(srcfilename));
    if (!srcfilepath)
        return PDFSYNCERR_OUTOFMEMORY;

    bool isUtf8 = true;
    char *mb_srcfilepath = str::conv::ToUtf8(srcfilepath);
TryAgainAnsi:
    if (!mb_srcfilepath)
        return PDFSYNCERR_OUTOFMEMORY;
    int ret = synctex_display_query(this->scanner, mb_srcfilepath, line, col);
    free(mb_srcfilepath);
    // recent SyncTeX versions encode in UTF-8 instead of ANSI
    if (isUtf8 && -1 == ret) {
        isUtf8 = false;
        mb_srcfilepath = str::conv::ToAnsi(srcfilepath);
        goto TryAgainAnsi;
    }

    if (-1 == ret)
        return PDFSYNCERR_UNKNOWN_SOURCEFILE;
    if (0 == ret)
        return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD;

    synctex_node_t node;
    int firstpage = -1;
    rects.Reset();

    while ((node = synctex_next_result(this->scanner)) != NULL) {
        if (firstpage == -1) {
            firstpage = synctex_node_page(node);
            if (firstpage <= 0 || firstpage > engine->PageCount())
                continue;
            *page = (UINT)firstpage;
        }
        if (synctex_node_page(node) != firstpage)
            continue;

        RectD rc;
        rc.x  = synctex_node_box_visible_h(node);
        rc.y  = synctex_node_box_visible_v(node) - synctex_node_box_visible_height(node);
        rc.dx = synctex_node_box_visible_width(node),
        rc.dy = synctex_node_box_visible_height(node) + synctex_node_box_visible_depth(node);
        rects.Push(rc.Round());
    }

    if (firstpage <= 0)
        return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD;
    return PDFSYNCERR_SUCCESS;
}
Example #15
0
bool PrintFile(BaseEngine *engine, WCHAR *printerName, bool displayErrors, const WCHAR *settings) {
    bool ok = false;
    //if (!HasPermission(Perm_PrinterAccess))
    //    return false;

#ifndef DISABLE_DOCUMENT_RESTRICTIONS
    if (engine && !engine->AllowsPrinting())
        engine = nullptr;
#endif
    if (!engine) {
        if (displayErrors)
            MessageBoxWarning(nullptr, _TR("Cannot print this file"), _TR("Printing problem."));
        return false;
    }

    ScopedMem<WCHAR> defaultPrinter;
    if (!printerName) {
        defaultPrinter.Set(GetDefaultPrinterName());
        printerName = defaultPrinter;
    }

    HANDLE printer;
    BOOL res = OpenPrinter(printerName, &printer, nullptr);
    if (!res) {
        if (displayErrors)
            MessageBoxWarning(nullptr, _TR("Printer with given name doesn't exist"),
                              _TR("Printing problem."));
        return false;
    }

    LONG returnCode = 0;
    LONG structSize = 0;
    LPDEVMODE devMode = nullptr;
    // get printer driver information
    DWORD needed = 0;
    GetPrinter(printer, 2, nullptr, 0, &needed);
    ScopedMem<PRINTER_INFO_2> infoData((PRINTER_INFO_2 *)AllocArray<BYTE>(needed));
    if (infoData)
        res = GetPrinter(printer, 2, (LPBYTE)infoData.Get(), needed, &needed);
    if (!res || !infoData || needed <= sizeof(PRINTER_INFO_2))
        goto Exit;

    structSize =
        DocumentProperties(nullptr, printer, printerName, nullptr, /* Asking for size, so */
                           nullptr,                                /* not used. */
                           0);                                     /* Zero returns buffer size. */
    if (structSize < sizeof(DEVMODE)) {
        // If failure, inform the user, cleanup and return failure.
        if (displayErrors)
            MessageBoxWarning(nullptr, _TR("Could not obtain Printer properties"),
                              _TR("Printing problem."));
        goto Exit;
    }
    devMode = (LPDEVMODE)malloc(structSize);
    if (!devMode)
        goto Exit;

    // Get the default DevMode for the printer and modify it for your needs.
    returnCode = DocumentProperties(nullptr, printer, printerName,
                                    devMode,        /* The address of the buffer to fill. */
                                    nullptr,        /* Not using the input buffer. */
                                    DM_OUT_BUFFER); /* Have the output buffer filled. */
    if (IDOK != returnCode) {
        // If failure, inform the user, cleanup and return failure.
        if (displayErrors)
            MessageBoxWarning(nullptr, _TR("Could not obtain Printer properties"),
                              _TR("Printing problem."));
        goto Exit;
    }

    ClosePrinter(printer);
    printer = nullptr;

    // set paper size to match the size of the document's first page
    // (will be overridden by any paper= value in -print-settings)
    devMode->dmPaperSize = GetPaperSize(engine);

    {
        Print_Advanced_Data advanced;
        Vec<PRINTPAGERANGE> ranges;

        ApplyPrintSettings(settings, engine->PageCount(), ranges, advanced, devMode);

        PrintData pd(engine, infoData, devMode, ranges, advanced);
        ok = PrintToDevice(pd);
        if (!ok && displayErrors)
            MessageBoxWarning(nullptr, _TR("Couldn't initialize printer"),
                              _TR("Printing problem."));
    }

Exit:
    free(devMode);
    if (printer)
        ClosePrinter(printer);
    return ok;
}
Example #16
0
void PdfCreator::SetProducerName(const WCHAR *name)
{
    if (!str::Eq(gPdfProducer, name))
        gPdfProducer.Set(str::Dup(name));
}
Example #17
0
int main(int argc, char **argv)
{
    setlocale(LC_ALL, "C");
    DisableDataExecution();

    WStrVec argList;
    ParseCmdLine(GetCommandLine(), argList);
    if (argList.Count() < 2) {
Usage:
        ErrOut("%s <filename> [-pwd <password>][-full][-alt][-render <path-%%d.tga>]\n",
            path::GetBaseName(argList.At(0)));
        return 2;
    }

    ScopedMem<WCHAR> filePath;
    WIN32_FIND_DATA fdata;
    HANDLE hfind = FindFirstFile(argList.At(1), &fdata);
    if (INVALID_HANDLE_VALUE != hfind) {
        ScopedMem<WCHAR> dir(path::GetDir(argList.At(1)));
        filePath.Set(path::Join(dir, fdata.cFileName));
        FindClose(hfind);
    }
    else {
        // embedded documents are referred to by an invalid path
        // containing more information after a colon (e.g. "C:\file.pdf:3:0")
        filePath.Set(str::Dup(argList.At(1)));
    }

    bool fullDump = false;
    WCHAR *password = NULL;
    WCHAR *renderPath = NULL;
    bool useAlternateHandlers = false;
    bool loadOnly = false, silent = false;
    int breakAlloc = 0;

    for (size_t i = 2; i < argList.Count(); i++) {
        if (str::Eq(argList.At(i), L"-full"))
            fullDump = true;
        else if (str::Eq(argList.At(i), L"-pwd") && i + 1 < argList.Count())
            password = argList.At(++i);
        else if (str::Eq(argList.At(i), L"-render") && i + 1 < argList.Count())
            renderPath = argList.At(++i);
        else if (str::Eq(argList.At(i), L"-alt"))
            useAlternateHandlers = true;
        // -loadonly and -silent are only meant for profiling
        else if (str::Eq(argList.At(i), L"-loadonly"))
            loadOnly = true;
        else if (str::Eq(argList.At(i), L"-silent"))
            silent = true;
#ifdef DEBUG
        else if (str::Eq(argList.At(i), L"-breakalloc") && i + 1 < argList.Count())
            breakAlloc = _wtoi(argList.At(++i));
#endif
        else
            goto Usage;
    }

#ifdef DEBUG
    if (breakAlloc) {
        _CrtSetBreakAlloc(breakAlloc);
        if (!IsDebuggerPresent())
            MessageBox(NULL, L"Keep your debugger ready for the allocation breakpoint...", L"EngineDump", MB_ICONINFORMATION);
    }
#endif
    if (silent) {
        FILE *nul;
        freopen_s(&nul, "NUL", "w", stdout);
        freopen_s(&nul, "NUL", "w", stderr);
    }

    // optionally use GDI+ rendering for PDF/XPS and the original ChmEngine for CHM
    DebugGdiPlusDevice(useAlternateHandlers);
    DebugAlternateChmEngine(!useAlternateHandlers);

    ScopedGdiPlus gdiPlus;
    DocType engineType;
    PasswordHolder pwdUI(password);
    BaseEngine *engine = EngineManager::CreateEngine(true, filePath, &pwdUI, &engineType);
    if (!engine) {
        ErrOut("Error: Couldn't create an engine for %s!\n", path::GetBaseName(filePath));
        return 1;
    }
    if (!loadOnly)
        DumpData(engine, fullDump);
    if (renderPath)
        RenderDocument(engine, renderPath, silent);
    delete engine;

#ifdef DEBUG
    // report memory leaks on stderr for engines that shouldn't leak
    if (engineType != Engine_DjVu) {
        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    }
#endif

    return 0;
}
Example #18
0
HRESULT CEpubFilter::GetNextChunkValue(CChunkValue &chunkValue)
{
    ScopedMem<WCHAR> str;

    switch (m_state) {
    case STATE_EPUB_START:
        m_state = STATE_EPUB_AUTHOR;
        chunkValue.SetTextValue(PKEY_PerceivedType, L"document");
        return S_OK;

    case STATE_EPUB_AUTHOR:
        m_state = STATE_EPUB_TITLE;
        str.Set(m_epubDoc->GetProperty(Prop_Author));
        if (!str::IsEmpty(str.Get())) {
            chunkValue.SetTextValue(PKEY_Author, str);
            return S_OK;
        }
        // fall through

    case STATE_EPUB_TITLE:
        m_state = STATE_EPUB_DATE;
        str.Set(m_epubDoc->GetProperty(Prop_Title));
        if (!str) str.Set(m_epubDoc->GetProperty(Prop_Subject));
        if (!str::IsEmpty(str.Get())) {
            chunkValue.SetTextValue(PKEY_Title, str);
            return S_OK;
        }
        // fall through

    case STATE_EPUB_DATE:
        m_state = STATE_EPUB_CONTENT;
        str.Set(m_epubDoc->GetProperty(Prop_ModificationDate));
        if (!str) str.Set(m_epubDoc->GetProperty(Prop_CreationDate));
        if (!str::IsEmpty(str.Get())) {
            SYSTEMTIME systime;
            if (IsoDateParse(str, &systime)) {
                FILETIME filetime;
                SystemTimeToFileTime(&systime, &filetime);
                chunkValue.SetFileTimeValue(PKEY_ItemDate, filetime);
                return S_OK;
            }
        }
        // fall through

    case STATE_EPUB_CONTENT:
        m_state = STATE_EPUB_END;
        str.Set(ExtractHtmlText(m_epubDoc));
        if (!str::IsEmpty(str.Get())) {
            chunkValue.SetTextValue(PKEY_Search_Contents, str, CHUNK_TEXT);
            return S_OK;
        }
        // fall through

    case STATE_EPUB_END:
    default:
        return FILTER_E_END_OF_CHUNKS;
    }
}
Example #19
0
static void RelayoutTocItem(LPNMTVCUSTOMDRAW ntvcd)
{
    // code inspired by http://www.codeguru.com/cpp/controls/treeview/multiview/article.php/c3985/
    LPNMCUSTOMDRAW ncd = &ntvcd->nmcd;
    HWND hTV = ncd->hdr.hwndFrom;
    HTREEITEM hItem = (HTREEITEM)ncd->dwItemSpec;
    RECT rcItem;
    if (0 == ncd->rc.right - ncd->rc.left || 0 == ncd->rc.bottom - ncd->rc.top)
        return;
    if (!TreeView_GetItemRect(hTV, hItem, &rcItem, TRUE))
        return;
    if (rcItem.right > ncd->rc.right)
        rcItem.right = ncd->rc.right;

    // Clear the label
    RECT rcFullWidth = rcItem;
    rcFullWidth.right = ncd->rc.right;
    FillRect(ncd->hdc, &rcFullWidth, GetSysColorBrush(COLOR_WINDOW));

    // Get the label's text
    WCHAR szText[MAX_PATH];
    TVITEM item;
    item.hItem = hItem;
    item.mask = TVIF_TEXT | TVIF_PARAM;
    item.pszText = szText;
    item.cchTextMax = MAX_PATH;
    TreeView_GetItem(hTV, &item);

    // Draw the page number right-aligned (if there is one)
    WindowInfo *win = FindWindowInfoByHwnd(hTV);
    DocTocItem *tocItem = (DocTocItem *)item.lParam;
    ScopedMem<WCHAR> label;
    if (tocItem->pageNo && win && win->IsDocLoaded()) {
        label.Set(win->ctrl->GetPageLabel(tocItem->pageNo));
        label.Set(str::Join(L"  ", label));
    }
    if (label && str::EndsWith(item.pszText, label)) {
        RECT rcPageNo = rcFullWidth;
        InflateRect(&rcPageNo, -2, -1);

        SIZE txtSize;
        GetTextExtentPoint32(ncd->hdc, label, str::Len(label), &txtSize);
        rcPageNo.left = rcPageNo.right - txtSize.cx;

        SetTextColor(ncd->hdc, GetSysColor(COLOR_WINDOWTEXT));
        SetBkColor(ncd->hdc, GetSysColor(COLOR_WINDOW));
        DrawText(ncd->hdc, label, -1, &rcPageNo, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);

        // Reduce the size of the label and cut off the page number
        rcItem.right = std::max(rcItem.right - txtSize.cx, 0);
        szText[str::Len(szText) - str::Len(label)] = '\0';
    }

    SetTextColor(ncd->hdc, ntvcd->clrText);
    SetBkColor(ncd->hdc, ntvcd->clrTextBk);

    // Draw the focus rectangle (including proper background color)
    HBRUSH brushBg = CreateSolidBrush(ntvcd->clrTextBk);
    FillRect(ncd->hdc, &rcItem, brushBg);
    DeleteObject(brushBg);
    if ((ncd->uItemState & CDIS_FOCUS))
        DrawFocusRect(ncd->hdc, &rcItem);

    InflateRect(&rcItem, -2, -1);
    DrawText(ncd->hdc, szText, -1, &rcItem, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_WORD_ELLIPSIS);
}
Example #20
0
static INT_PTR CALLBACK Dialog_Settings_Proc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    GlobalPrefs *prefs;

    switch (msg)
    {
    case WM_INITDIALOG:
        prefs = (GlobalPrefs *)lParam;
        assert(prefs);
        SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)prefs);

        // Fill the page layouts into the select box
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Automatic"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Single Page"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Facing"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Book View"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Continuous"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Continuous Facing"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_ADDSTRING, 0, (LPARAM)_TR("Continuous Book View"));
        SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_SETCURSEL, prefs->defaultDisplayModeEnum - DM_FIRST, 0);

        SetupZoomComboBox(hDlg, IDC_DEFAULT_ZOOM, false, prefs->defaultZoom);

        CheckDlgButton(hDlg, IDC_DEFAULT_SHOW_TOC, prefs->tocVisible ? BST_CHECKED : BST_UNCHECKED);
        CheckDlgButton(hDlg, IDC_GLOBAL_PREFS_ONLY, !prefs->globalPrefsOnly ? BST_CHECKED : BST_UNCHECKED);
        EnableWindow(GetDlgItem(hDlg, IDC_GLOBAL_PREFS_ONLY), prefs->rememberOpenedFiles);
        CheckDlgButton(hDlg, IDC_USE_SYS_COLORS, prefs->useSysColors ? BST_CHECKED : BST_UNCHECKED);
        CheckDlgButton(hDlg, IDC_AUTO_UPDATE_CHECKS, prefs->enableAutoUpdate ? BST_CHECKED : BST_UNCHECKED);
        EnableWindow(GetDlgItem(hDlg, IDC_AUTO_UPDATE_CHECKS), HasPermission(Perm_InternetAccess));
        CheckDlgButton(hDlg, IDC_REMEMBER_OPENED_FILES, prefs->rememberOpenedFiles ? BST_CHECKED : BST_UNCHECKED);
        if (IsExeAssociatedWithPdfExtension()) {
            SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("SumatraPDF is your default PDF reader"));
            EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), FALSE);
        } else if (IsRunningInPortableMode()) {
            SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("Default PDF reader can't be changed in portable mode"));
            EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), FALSE);
        } else {
            SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("Make SumatraPDF my default PDF reader"));
            EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), HasPermission(Perm_RegistryAccess));
        }

        win::SetText(hDlg, _TR("SumatraPDF Options"));
        SetDlgItemText(hDlg, IDC_SECTION_VIEW, _TR("View"));
        SetDlgItemText(hDlg, IDC_DEFAULT_LAYOUT_LABEL, _TR("Default &Layout:"));
        SetDlgItemText(hDlg, IDC_DEFAULT_ZOOM_LABEL, _TR("Default &Zoom:"));
        SetDlgItemText(hDlg, IDC_DEFAULT_SHOW_TOC, _TR("Show the &bookmarks sidebar when available"));
        SetDlgItemText(hDlg, IDC_GLOBAL_PREFS_ONLY, _TR("&Remember these settings for each document"));
        SetDlgItemText(hDlg, IDC_USE_SYS_COLORS, _TR("Replace document &colors with Windows color scheme"));
        SetDlgItemText(hDlg, IDC_SECTION_ADVANCED, _TR("Advanced"));
        SetDlgItemText(hDlg, IDC_AUTO_UPDATE_CHECKS, _TR("Automatically check for &updates"));
        SetDlgItemText(hDlg, IDC_REMEMBER_OPENED_FILES, _TR("Remember &opened files"));
        SetDlgItemText(hDlg, IDC_SECTION_INVERSESEARCH, _TR("Set inverse search command-line"));
        SetDlgItemText(hDlg, IDC_CMDLINE_LABEL, _TR("Enter the command-line to invoke when you double-click on the PDF document:"));
        SetDlgItemText(hDlg, IDOK, _TR("OK"));
        SetDlgItemText(hDlg, IDCANCEL, _TR("Cancel"));

        if (GetSysColor(COLOR_WINDOWTEXT) == RGB(0, 0, 0) &&
            GetSysColor(COLOR_WINDOW) == RGB(0xFF, 0xFF, 0xFF)) {
            // remove the "use system colors" item if it wouldn't change anything
            RemoveDialogItem(hDlg, IDC_USE_SYS_COLORS);
        }

        if (prefs->enableTeXEnhancements && HasPermission(Perm_DiskAccess)) {
            // Fill the combo with the list of possible inverse search commands
            // Try to select a correct default when first showing this dialog
            const WCHAR *cmdLine = prefs->inverseSearchCmdLine;
            ScopedMem<WCHAR> inverseSearch;
            if (!cmdLine) {
                inverseSearch.Set(AutoDetectInverseSearchCommands(GetDlgItem(hDlg, IDC_CMDLINE)));
                cmdLine = inverseSearch;
            }
            // Find the index of the active command line
            LRESULT ind = SendMessage(GetDlgItem(hDlg, IDC_CMDLINE), CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM) cmdLine);
            if (CB_ERR == ind) {
                // if no existing command was selected then set the user custom command in the combo
                ComboBox_AddItemData(GetDlgItem(hDlg, IDC_CMDLINE), cmdLine);
                SetDlgItemText(hDlg, IDC_CMDLINE, cmdLine);
            }
            else {
                // select the active command
                SendMessage(GetDlgItem(hDlg, IDC_CMDLINE), CB_SETCURSEL, (WPARAM) ind , 0);
            }
        }
        else {
            RemoveDialogItem(hDlg, IDC_SECTION_INVERSESEARCH, IDC_SECTION_ADVANCED);
        }

        CenterDialog(hDlg);
        SetFocus(GetDlgItem(hDlg, IDC_DEFAULT_LAYOUT));
        return FALSE;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDOK:
            prefs = (GlobalPrefs *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
            assert(prefs);
            prefs->defaultDisplayModeEnum = (DisplayMode)(SendDlgItemMessage(hDlg, IDC_DEFAULT_LAYOUT, CB_GETCURSEL, 0, 0) + DM_FIRST);
            prefs->defaultZoom = GetZoomComboBoxValue(hDlg, IDC_DEFAULT_ZOOM, false, prefs->defaultZoom);

            prefs->tocVisible = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_DEFAULT_SHOW_TOC));
            prefs->globalPrefsOnly = (BST_CHECKED != IsDlgButtonChecked(hDlg, IDC_GLOBAL_PREFS_ONLY));
            prefs->useSysColors = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_SYS_COLORS));
            prefs->enableAutoUpdate = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_AUTO_UPDATE_CHECKS));
            prefs->rememberOpenedFiles = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_REMEMBER_OPENED_FILES));
            if (prefs->enableTeXEnhancements && HasPermission(Perm_DiskAccess)) {
                free(prefs->inverseSearchCmdLine);
                prefs->inverseSearchCmdLine = win::GetText(GetDlgItem(hDlg, IDC_CMDLINE));
            }
            EndDialog(hDlg, IDOK);
            return TRUE;

        case IDCANCEL:
            EndDialog(hDlg, IDCANCEL);
            return TRUE;

        case IDC_REMEMBER_OPENED_FILES:
            {
                bool rememberOpenedFiles = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_REMEMBER_OPENED_FILES));
                EnableWindow(GetDlgItem(hDlg, IDC_GLOBAL_PREFS_ONLY), rememberOpenedFiles);
            }
            return TRUE;

        case IDC_DEFAULT_SHOW_TOC:
        case IDC_GLOBAL_PREFS_ONLY:
        case IDC_AUTO_UPDATE_CHECKS:
            return TRUE;

        case IDC_SET_DEFAULT_READER:
            if (!HasPermission(Perm_RegistryAccess))
                return TRUE;
            AssociateExeWithPdfExtension();
            if (IsExeAssociatedWithPdfExtension()) {
                SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("SumatraPDF is your default PDF reader"));
                EnableWindow(GetDlgItem(hDlg, IDC_SET_DEFAULT_READER), FALSE);
                SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDOK), TRUE);
            }
            else {
                SetDlgItemText(hDlg, IDC_SET_DEFAULT_READER, _TR("SumatraPDF should now be your default PDF reader"));
            }
            return TRUE;
        }
        break;
    }
    return FALSE;
}
Example #21
0
int Pdfsync::DocToSource(UINT pageNo, PointI pt, ScopedMem<WCHAR>& filename, UINT *line, UINT *col)
{
    if (IsIndexDiscarded())
        if (RebuildIndex() != PDFSYNCERR_SUCCESS)
            return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED;

    // find the entry in the index corresponding to this page
    if (pageNo <= 0 || pageNo >= sheetIndex.Count() || pageNo > (UINT)engine->PageCount())
        return PDFSYNCERR_INVALID_PAGE_NUMBER;

    // PdfSync coordinates are y-inversed
    RectI mbox = engine->PageMediabox(pageNo).Round();
    pt.y = mbox.dy - pt.y;

    // distance to the closest pdf location (in the range <PDFSYNC_EPSILON_SQUARE)
    UINT closest_xydist = UINT_MAX;
    UINT selected_record = UINT_MAX;
    // If no record is found within a distance^2 of PDFSYNC_EPSILON_SQUARE
    // (selected_record == -1) then we pick up the record that is closest
    // vertically to the hit-point.
    UINT closest_ydist = UINT_MAX; // vertical distance between the hit point and the vertically-closest record
    UINT closest_xdist = UINT_MAX; // horizontal distance between the hit point and the vertically-closest record
    UINT closest_ydist_record = UINT_MAX; // vertically-closest record

    // read all the sections of 'p' declarations for this pdf sheet
    for (size_t i = sheetIndex.At(pageNo); i < points.Count() && points.At(i).page == pageNo; i++) {
        // check whether it is closer than the closest point found so far
        UINT dx = abs(pt.x - (int)SYNC_TO_PDF_COORDINATE(points.At(i).x));
        UINT dy = abs(pt.y - (int)SYNC_TO_PDF_COORDINATE(points.At(i).y));
        UINT dist = dx * dx + dy * dy;
        if (dist < PDFSYNC_EPSILON_SQUARE && dist < closest_xydist) {
            selected_record = points.At(i).record;
            closest_xydist = dist;
        }
        else if ((closest_xydist == UINT_MAX) && dy < PDFSYNC_EPSILON_Y &&
                 (dy < closest_ydist || (dy == closest_ydist && dx < closest_xdist))) {
            closest_ydist_record = points.At(i).record;
            closest_ydist = dy;
            closest_xdist = dx;
        }
    }

    if (selected_record == UINT_MAX)
        selected_record = closest_ydist_record;
    if (selected_record == UINT_MAX)
        return PDFSYNCERR_NO_SYNC_AT_LOCATION; // no record was found close enough to the hit point

    // We have a record number, we need to find its declaration ('l ...') in the syncfile
    PdfsyncLine cmp;
    cmp.record = selected_record;
    PdfsyncLine *found = (PdfsyncLine *)bsearch(&cmp, lines.LendData(), lines.Count(), sizeof(PdfsyncLine), cmpLineRecords);
    assert(found);
    if (!found)
        return PDFSYNCERR_NO_SYNC_AT_LOCATION;

    filename.Set(str::Dup(srcfiles.At(found->file)));
    *line = found->line;
    *col = found->column;

    return PDFSYNCERR_SUCCESS;
}
Example #22
0
static void DeserializeAdvancedSettings(const WCHAR *filepath, SettingInfo *info, size_t count, void *structBase)
{
    char *base = (char *)structBase;
    const WCHAR *section = NULL;
    INT intValue, intValueDef;
    ScopedMem<WCHAR> strValue;

    for (size_t i = 0; i < count; i++) {
        SettingInfo& meta = info[i];
        CrashIf(meta.type != SType_Section && !section);
        switch (meta.type) {
        case SType_Section:
            section = meta.name;
            break;
        case SType_Bool:
            intValueDef = *(bool *)(base + meta.offset) ? 1 : 0;
            intValue = GetPrivateProfileInt(section, meta.name, intValueDef, filepath);
            *(bool *)(base + meta.offset) = intValue != 0;
            break;
        case SType_Color:
            strValue.Set(ReadIniString(filepath, section, meta.name));
            if (str::Parse(strValue, L"#%6x", &intValue))
                *(COLORREF *)(base + meta.offset) = (COLORREF)intValue;
            break;
        case SType_Int:
            intValueDef = *(int *)(base + meta.offset);
            intValue = GetPrivateProfileInt(section, meta.name, intValueDef, filepath);
            *(int *)(base + meta.offset) = intValue;
            break;
        case SType_String:
            strValue.Set(ReadIniString(filepath, section, meta.name, L"\n"));
            if (!str::Eq(strValue, L"\n"))
                ((ScopedMem<WCHAR> *)(base + meta.offset))->Set(strValue.StealData());
            break;
        case SType_BoolVec:
        case SType_ColorVec:
        case SType_IntVec:
        case SType_StringVec:
            ScopedMem<WCHAR> sections(ReadIniString(filepath, section, NULL));
            for (const WCHAR *name = sections; *name; name += str::Len(name) + 1) {
                UINT idx;
                if (str::Eq(str::Parse(name, L"%u.", &idx), meta.name)) {
                    if (SType_BoolVec == meta.type) {
                        bool value = GetPrivateProfileInt(section, name, 0, filepath) != 0;
                        ((Vec<bool> *)(base + meta.offset))->InsertAt(idx, value);
                    }
                    else if (SType_ColorVec == meta.type) {
                        strValue.Set(ReadIniString(filepath, section, name));
                        if (str::Parse(strValue, L"#%6x", &intValue)) {
                            COLORREF value = (COLORREF)intValue;
                            ((Vec<COLORREF> *)(base + meta.offset))->InsertAt(idx, value);
                        }
                    }
                    else if (SType_IntVec == meta.type) {
                        intValue = GetPrivateProfileInt(section, name, 0, filepath);
                        ((Vec<int> *)(base + meta.offset))->InsertAt(idx, intValue);
                    }
                    else {
                        strValue.Set(ReadIniString(filepath, section, name));
                        WStrVec *strVec = (WStrVec *)(base + meta.offset);
                        // TODO: shouldn't InsertAt free the previous string?
                        if (idx < strVec->Count())
                            free(strVec->At(idx));
                        strVec->InsertAt(idx, strValue.StealData());
                    }
                }
            }
            break;
        }
    }
}