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(); }
WCHAR* ChmDoc::GetProperty(DocumentProperty prop) { AutoFreeW result; if (DocumentProperty::Title == prop && title) result.Set(ToStr(title)); else if (DocumentProperty::CreatorApp == prop && creator) result.Set(ToStr(creator)); // TODO: shouldn't it be up to the front-end to normalize whitespace? if (result) { // TODO: original code called str::RemoveChars(result, "\n\r\t") str::NormalizeWS(result); } return result.StealData(); }
static void AppendFavMenuItems(HMENU m, DisplayState* f, UINT& idx, bool combined, bool isCurrent) { for (size_t i = 0; i < f->favorites->size(); i++) { if (i >= MAX_FAV_MENUS) { return; } Favorite* fn = f->favorites->at(i); fn->menuId = idx++; AutoFreeW s; if (combined) { s.Set(FavCompactReadableName(f, fn, isCurrent)); } else { s.Set(FavReadableName(fn)); } auto str = win::menu::ToSafeString(s); AppendMenuW(m, MF_STRING, (UINT_PTR)fn->menuId, str); } }
int SyncTex::DocToSource(UINT pageNo, PointI pt, AutoFreeW& filename, UINT* line, UINT* col) { if (IsIndexDiscarded()) { if (RebuildIndex() != PDFSYNCERR_SUCCESS) return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED; } CrashIf(!this->scanner); // Coverity: at this point, this->scanner->flags.has_parsed == 1 and thus // synctex_scanner_parse never gets the chance to freeing the scanner if (synctex_edit_query(this->scanner, pageNo, (float)pt.x, (float)pt.y) <= 0) return PDFSYNCERR_NO_SYNC_AT_LOCATION; synctex_node_t node = synctex_next_result(this->scanner); if (!node) return PDFSYNCERR_NO_SYNC_AT_LOCATION; const char* name = synctex_scanner_get_name(this->scanner, synctex_node_tag(node)); if (!name) return PDFSYNCERR_UNKNOWN_SOURCEFILE; bool isUtf8 = true; filename.Set(str::conv::FromUtf8(name)); TryAgainAnsi: if (!filename) return PDFSYNCERR_OUTOFMEMORY; // undecorate the filepath: replace * by space and / by \ (backslash) str::TransChars(filename, L"*/", L" \\"); // Convert the source filepath to an absolute path if (PathIsRelative(filename)) filename.Set(PrependDir(filename)); // recent SyncTeX versions encode in UTF-8 instead of ANSI if (isUtf8 && !file::Exists(filename)) { isUtf8 = false; filename.Set(str::conv::FromAnsi(name)); goto TryAgainAnsi; } *line = synctex_node_line(node); *col = synctex_node_column(node); return PDFSYNCERR_SUCCESS; }
HRESULT CPdfFilter::GetNextChunkValue(CChunkValue& chunkValue) { AutoFreeW 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(DocumentProperty::Author)); if (!str::IsEmpty(str.Get())) { chunkValue.SetTextValue(PKEY_Author, str); return S_OK; } // fall through case STATE_PDF_TITLE: m_state = STATE_PDF_DATE; str.Set(m_pdfEngine->GetProperty(DocumentProperty::Title)); if (!str) str.Set(m_pdfEngine->GetProperty(DocumentProperty::Subject)); if (!str::IsEmpty(str.Get())) { chunkValue.SetTextValue(PKEY_Title, str); return S_OK; } // fall through case STATE_PDF_DATE: m_state = STATE_PDF_CONTENT; str.Set(m_pdfEngine->GetProperty(DocumentProperty::ModificationDate)); if (!str) str.Set(m_pdfEngine->GetProperty(DocumentProperty::CreationDate)); if (!str::IsEmpty(str.Get())) { SYSTEMTIME systime; FILETIME filetime; if (PdfDateParse(str, &systime) && 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, L"\r\n")); if (str::IsEmpty(str.Get())) continue; chunkValue.SetTextValue(PKEY_Search_Contents, str, CHUNK_TEXT); return S_OK; } m_state = STATE_PDF_END; // fall through case STATE_PDF_END: default: return FILTER_E_END_OF_CHUNKS; } }
// Find a record corresponding to the given source file, line number and optionally column number. // (at the moment the column parameter is ignored) // // If there are several *consecutively declared* records for the same line then they are all returned. // The list of records is added to the vector 'records' // // If there is no record for that line, the record corresponding to the nearest line is selected // (within a range of EPSILON_LINE) // // The function returns PDFSYNCERR_SUCCESS if a matching record was found. UINT Pdfsync::SourceToRecord(const WCHAR* srcfilename, UINT line, UINT col, Vec<size_t>& records) { UNUSED(col); if (!srcfilename) return PDFSYNCERR_INVALID_ARGUMENT; AutoFreeW srcfilepath; // convert the source file to an absolute path if (PathIsRelative(srcfilename)) srcfilepath.Set(PrependDir(srcfilename)); else srcfilepath.SetCopy(srcfilename); if (!srcfilepath) return PDFSYNCERR_OUTOFMEMORY; // find the source file entry size_t isrc; for (isrc = 0; isrc < srcfiles.size(); isrc++) if (path::IsSame(srcfilepath, srcfiles.at(isrc))) break; if (isrc == srcfiles.size()) return PDFSYNCERR_UNKNOWN_SOURCEFILE; if (fileIndex.at(isrc).start == fileIndex.at(isrc).end) return PDFSYNCERR_NORECORD_IN_SOURCEFILE; // there is not any record declaration for that particular source file // look for sections belonging to the specified file // starting with the first section that is declared within the scope of the file. UINT min_distance = EPSILON_LINE; // distance to the closest record size_t lineIx = (size_t)-1; // closest record-line index for (size_t isec = fileIndex.at(isrc).start; isec < fileIndex.at(isrc).end; isec++) { // does this section belong to the desired file? if (lines.at(isec).file != isrc) continue; UINT d = abs((int)lines.at(isec).line - (int)line); if (d < min_distance) { min_distance = d; lineIx = isec; if (0 == d) break; // We have found a record for the requested line! } } if (lineIx == (size_t)-1) return PDFSYNCERR_NORECORD_FOR_THATLINE; // we read all the consecutive records until we reach a record belonging to another line for (size_t i = lineIx; i < lines.size() && lines.at(i).line == lines.at(lineIx).line; i++) records.Push(lines.at(i).record); return PDFSYNCERR_SUCCESS; }
HRESULT CEpubFilter::GetNextChunkValue(CChunkValue& chunkValue) { AutoFreeW 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(DocumentProperty::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(DocumentProperty::Title)); if (!str) str.Set(m_epubDoc->GetProperty(DocumentProperty::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(DocumentProperty::ModificationDate)); if (!str) str.Set(m_epubDoc->GetProperty(DocumentProperty::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; } }
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; } AssertCrash(this->scanner); AutoFreeW srcfilepath; // convert the source file to an absolute path if (PathIsRelative(srcfilename)) srcfilepath.Set(PrependDir(srcfilename)); else srcfilepath.SetCopy(srcfilename); if (!srcfilepath) return PDFSYNCERR_OUTOFMEMORY; bool isUtf8 = true; char* mb_srcfilepath = str::conv::ToUtf8(srcfilepath).StealData(); 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).StealData(); 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)) != nullptr) { 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; }