void AddToList() { bool hasFootnotes = footnotes.length() > 0; if ( !pageend ) pageend = pagestart; if ( !pagestart && !hasFootnotes ) return; int start = (pagestart && pageend) ? pagestart->getStart() : lastpageend; int h = (pagestart && pageend) ? pageend->getEnd()-pagestart->getStart() : 0; #ifdef DEBUG_FOOTNOTES if ( CRLog::isTraceEnabled() ) { if ( pagestart && pageend ) { //CRLog::trace("AddToList(%d, %d) footnotes: %d pageHeight=%d", pagestart->start, pageend->start+pageend->height, footnotes.length(), h); } else { //CRLog::trace("AddToList(Only footnote: %d) footnotes: %d pageHeight=%d", lastpageend, footnotes.length(), h); } } #endif LVRendPageInfo * page = new LVRendPageInfo(start, h, page_list->length()); lastpageend = start + h;//上一页末尾高度 if ( footnotes.length()>0 ) { page->footnotes.add( footnotes ); footnotes.clear(); footheight = 0; } page_list->add(page); }
void moveBy( int delta ) { current_ += delta; if ( current_ < 0 ) current_ = candidates_.length()-1; if ( current_ >= candidates_.length() ) current_ = 0; if ( current_ < 0 ) current_ = 0; if ( candidates_.length() ) words_.highlight(candidates_[current_]); }
void init() { _words.clear(); //ldomDocument * doc = docview.getDocument(); int pageIndex = -1; //docview.getCurPage(); LVRef<ldomXRange> range = docview_.getPageDocumentRange( pageIndex ); crtrace trace; if( !range.isNull() ) { LVArray<ldomWord> words; range->getRangeWords(words); for ( int i=0; i<words.length(); i++ ) { lString16 w = words[i].getText(); lString8 encoded = encoding_.encode_string( w ); if ( w.length() < DICT_MIN_WORD_LENGTH ) continue; /* trace << "string " << w << " encoded as " << encoded << "\n"; */ int index = -1; for ( int j=0; j<_words.length(); j++ ) if ( _words[j]->equals(w) ) { index = j; break; } if ( index>=0 ) _words[index]->add( words[i] ); // add range to existing word else _words.add( new WordWithRanges( w, encoded, words[i] ) ); // add new word } } }
virtual ~LVRtfPictDestination() { if (!_fmt || _buf.empty()) return; // add Image BLOB lString16 name(BLOB_NAME_PREFIX); // L"@blob#" name << L"image"; name << lString16::itoa(m_parser.nextImageIndex()); name << (_fmt==rtf_img_jpeg ? L".jpg" : L".png"); m_callback->OnBlob(name, _buf.get(), _buf.length()); #if 0 { LVStreamRef stream = LVOpenFileStream((lString16(L"/tmp/") + name).c_str(), LVOM_WRITE); stream->Write(_buf.get(), _buf.length(), NULL); } #endif m_callback->OnTagOpen(LXML_NS_NONE, L"img"); m_callback->OnAttribute(LXML_NS_NONE, L"src", name.c_str()); m_callback->OnTagClose(LXML_NS_NONE, L"img"); }
bool setManglingKey(lString16 key) { if (key.startsWith(lString16(L"urn:uuid:"))) key = key.substr(9); _fontManglingKey.clear(); _fontManglingKey.reserve(16); lUInt8 b = 0; int n = 0; for (int i=0; i<key.length(); i++) { int d = hexDigit(key[i]); if (d>=0) { b = (b << 4) | d; if (++n > 1) { _fontManglingKey.add(b); n = 0; b = 0; } } } return _fontManglingKey.length() == 16; }
bool ImportEpubDocument( LVStreamRef stream, ldomDocument * m_doc, LVDocViewCallback * progressCallback, CacheLoadingCallback * formatCallback ) { LVContainerRef arc = LVOpenArchieve( stream ); if ( arc.isNull() ) return false; // not a ZIP archive // check root media type lString16 rootfilePath = EpubGetRootFilePath(arc); if ( rootfilePath.empty() ) return false; EncryptedDataContainer * decryptor = new EncryptedDataContainer(arc); if (decryptor->open()) { CRLog::debug("EPUB: encrypted items detected"); } LVContainerRef m_arc = LVContainerRef(decryptor); if (decryptor->hasUnsupportedEncryption()) { // DRM!!! createEncryptedEpubWarningDocument(m_doc); return true; } m_doc->setContainer(m_arc); // read content.opf EpubItems epubItems; //EpubItem * epubToc = NULL; //TODO LVArray<EpubItem*> spineItems; lString16 codeBase; //lString16 css; // { codeBase=LVExtractPath(rootfilePath, false); CRLog::trace("codeBase=%s", LCSTR(codeBase)); } LVStreamRef content_stream = m_arc->OpenStream(rootfilePath.c_str(), LVOM_READ); if ( content_stream.isNull() ) return false; lString16 ncxHref; lString16 coverId; LVEmbeddedFontList fontList; EmbeddedFontStyleParser styleParser(fontList); // reading content stream { ldomDocument * doc = LVParseXMLStream( content_stream ); if ( !doc ) return false; CRPropRef m_doc_props = m_doc->getProps(); lString16 author = doc->textFromXPath( lString16(L"package/metadata/creator")); lString16 title = doc->textFromXPath( lString16(L"package/metadata/title")); m_doc_props->setString(DOC_PROP_TITLE, title); m_doc_props->setString(DOC_PROP_AUTHORS, author ); for ( int i=1; i<50; i++ ) { ldomNode * item = doc->nodeFromXPath( lString16(L"package/metadata/identifier[") + lString16::itoa(i) + L"]" ); if (!item) break; lString16 key = item->getText(); if (decryptor->setManglingKey(key)) { CRLog::debug("Using font mangling key %s", LCSTR(key)); break; } } CRLog::info("Author: %s Title: %s", LCSTR(author), LCSTR(title)); for ( int i=1; i<20; i++ ) { ldomNode * item = doc->nodeFromXPath( lString16(L"package/metadata/meta[") + lString16::itoa(i) + L"]" ); if ( !item ) break; lString16 name = item->getAttributeValue(L"name"); lString16 content = item->getAttributeValue(L"content"); if ( name == L"cover" ) coverId = content; else if ( name==L"calibre:series" ) m_doc_props->setString(DOC_PROP_SERIES_NAME, content ); else if ( name==L"calibre:series_index" ) m_doc_props->setInt(DOC_PROP_SERIES_NUMBER, content.atoi() ); } // items for ( int i=1; i<50000; i++ ) { ldomNode * item = doc->nodeFromXPath( lString16(L"package/manifest/item[") + lString16::itoa(i) + L"]" ); if ( !item ) break; lString16 href = item->getAttributeValue(L"href"); lString16 mediaType = item->getAttributeValue(L"media-type"); lString16 id = item->getAttributeValue(L"id"); if ( !href.empty() && !id.empty() ) { if ( id==coverId ) { // coverpage file lString16 coverFileName = codeBase + href; CRLog::info("EPUB coverpage file: %s", LCSTR(coverFileName)); LVStreamRef stream = m_arc->OpenStream(coverFileName.c_str(), LVOM_READ); if ( !stream.isNull() ) { LVImageSourceRef img = LVCreateStreamImageSource(stream); if ( !img.isNull() ) { CRLog::info("EPUB coverpage image is correct: %d x %d", img->GetWidth(), img->GetHeight() ); m_doc_props->setString(DOC_PROP_COVER_FILE, coverFileName); } } } EpubItem * epubItem = new EpubItem; epubItem->href = href; epubItem->id = id; epubItem->mediaType = mediaType; epubItems.add( epubItem ); // // register embedded document fonts // if (mediaType == L"application/vnd.ms-opentype" // || mediaType == L"application/x-font-otf" // || mediaType == L"application/x-font-ttf") { // TODO: more media types? // // TODO: // fontList.add(codeBase + href); // } } if ( mediaType==L"text/css" ) { lString16 name = LVCombinePaths(codeBase, href); LVStreamRef cssStream = m_arc->OpenStream(name.c_str(), LVOM_READ); if (!cssStream.isNull()) { lString8 cssFile = UnicodeToUtf8(LVReadTextFile(cssStream)); lString16 base = name; LVExtractLastPathElement(base); CRLog::trace("style: %s", cssFile.c_str()); styleParser.parse(base, cssFile); } } } // spine == itemrefs if ( epubItems.length()>0 ) { ldomNode * spine = doc->nodeFromXPath( lString16(L"package/spine") ); if ( spine ) { EpubItem * ncx = epubItems.findById( spine->getAttributeValue(L"toc") ); //TODO //EpubItem * ncx = epubItems.findById(lString16("ncx")); if ( ncx!=NULL ) ncxHref = codeBase + ncx->href; for ( int i=1; i<50000; i++ ) { ldomNode * item = doc->nodeFromXPath( lString16(L"package/spine/itemref[") + lString16::itoa(i) + L"]" ); if ( !item ) break; EpubItem * epubItem = epubItems.findById( item->getAttributeValue(L"idref") ); if ( epubItem ) { // TODO: add to document spineItems.add( epubItem ); } } } } delete doc; } if ( spineItems.length()==0 ) return false; #if BUILD_LITE!=1 if ( m_doc->openFromCache(formatCallback) ) { if ( progressCallback ) { progressCallback->OnLoadFileEnd( ); } return true; } #endif lUInt32 saveFlags = m_doc->getDocFlags(); m_doc->setDocFlags( saveFlags ); m_doc->setContainer( m_arc ); ldomDocumentWriter writer(m_doc); #if 0 m_doc->setNodeTypes( fb2_elem_table ); m_doc->setAttributeTypes( fb2_attr_table ); m_doc->setNameSpaceTypes( fb2_ns_table ); #endif //m_doc->setCodeBase( codeBase ); ldomDocumentFragmentWriter appender(&writer, lString16(L"body"), lString16(L"DocFragment"), lString16::empty_str ); writer.OnStart(NULL); writer.OnTagOpenNoAttr(L"", L"body"); int fragmentCount = 0; for ( int i=0; i<spineItems.length(); i++ ) { if ( spineItems[i]->mediaType==L"application/xhtml+xml" ) { lString16 name = codeBase + spineItems[i]->href; appender.addPathSubstitution( name, lString16(L"_doc_fragment_") + lString16::itoa(i) ); } } for ( int i=0; i<spineItems.length(); i++ ) { if ( spineItems[i]->mediaType==L"application/xhtml+xml" ) { lString16 name = codeBase + spineItems[i]->href; { CRLog::debug("Checking fragment: %s", LCSTR(name)); LVStreamRef stream = m_arc->OpenStream(name.c_str(), LVOM_READ); if ( !stream.isNull() ) { appender.setCodeBase( name ); lString16 base = name; LVExtractLastPathElement(base); //CRLog::trace("base: %s", LCSTR(base)); //LVXMLParser LVHTMLParser parser(stream, &appender); if ( parser.CheckFormat() && parser.Parse() ) { // valid fragmentCount++; lString8 headCss = appender.getHeadStyleText(); //CRLog::trace("style: %s", headCss.c_str()); styleParser.parse(base, headCss); } else { CRLog::error("Document type is not XML/XHTML for fragment %s", LCSTR(name)); } } } } } ldomDocument * ncxdoc = NULL; if ( !ncxHref.empty() ) { LVStreamRef stream = m_arc->OpenStream(ncxHref.c_str(), LVOM_READ); lString16 codeBase = LVExtractPath( ncxHref ); if ( codeBase.length()>0 && codeBase.lastChar()!='/' ) codeBase.append(1, L'/'); appender.setCodeBase(codeBase); if ( !stream.isNull() ) { ldomDocument * ncxdoc = LVParseXMLStream( stream ); if ( ncxdoc!=NULL ) { ldomNode * navMap = ncxdoc->nodeFromXPath( lString16(L"ncx/navMap")); if ( navMap!=NULL ) ReadEpubToc( m_doc, navMap, m_doc->getToc(), appender ); delete ncxdoc; } } } writer.OnTagClose(L"", L"body"); writer.OnStop(); CRLog::debug("EPUB: %d documents merged", fragmentCount); if (!fontList.empty()) { // set document font list, and register fonts m_doc->getEmbeddedFontList().set(fontList); m_doc->registerEmbeddedFonts(); m_doc->forceReinitStyles(); } if ( fragmentCount==0 ) return false; #if 0 // set stylesheet //m_doc->getStyleSheet()->clear(); m_doc->setStyleSheet( NULL, true ); //m_doc->getStyleSheet()->parse(m_stylesheet.c_str()); if ( !css.empty() && m_doc->getDocFlag(DOC_FLAG_ENABLE_INTERNAL_STYLES) ) { m_doc->setStyleSheet( "p.p { text-align: justify }\n" "svg { text-align: center }\n" "i { display: inline; font-style: italic }\n" "b { display: inline; font-weight: bold }\n" "abbr { display: inline }\n" "acronym { display: inline }\n" "address { display: inline }\n" "p.title-p { hyphenate: none }\n" //abbr, acronym, address, blockquote, br, cite, code, dfn, div, em, h1, h2, h3, h4, h5, h6, kbd, p, pre, q, samp, span, strong, var , false); m_doc->setStyleSheet( UnicodeToUtf8(css).c_str(), false ); //m_doc->getStyleSheet()->parse(UnicodeToUtf8(css).c_str()); } else { //m_doc->getStyleSheet()->parse(m_stylesheet.c_str()); //m_doc->setStyleSheet( m_stylesheet.c_str(), false ); } #endif #if 0 LVStreamRef out = LVOpenFileStream( L"c:\\doc.xml" , LVOM_WRITE ); if ( !out.isNull() ) m_doc->saveToStream( out, "utf-8" ); #endif // DONE! if ( progressCallback ) { progressCallback->OnLoadFileEnd( ); m_doc->compact(); m_doc->dumpStatistics(); } return true; }
const lString16 get() { if ( current_ >= 0 && current_ < candidates_.length() ) return candidates_[current_]->getWord(); return lString16::empty_str; }
static int findText(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); const char *l_pattern = luaL_checkstring(L, 2); lString16 pattern = lString16(l_pattern); int origin = luaL_checkint(L, 3); bool reverse = luaL_checkint(L, 4); bool caseInsensitive = luaL_checkint(L, 5); if ( pattern.empty() ) return 0; LVArray<ldomWord> words; lvRect rc; doc->text_view->GetPos( rc ); int pageHeight = rc.height(); int start = -1; int end = -1; if ( reverse ) { // backward if ( origin == 0 ) { // from end of current page to first page end = rc.bottom; } else if ( origin == -1 ) { // from the last page to end of current page start = rc.bottom + 1; } else { // origin == 1 // from prev page to the first page end = rc.top - 1; } } else { // forward if ( origin == 0 ) { // from current page to the last page start = rc.top; } else if ( origin == -1 ) { // from the first page to current page end = rc.top + 1; } else { // origin == 1 // from next page to the last page start = rc.bottom + 1; } } CRLog::debug("CRViewDialog::findText: Current page: %d .. %d", rc.top, rc.bottom); CRLog::debug("CRViewDialog::findText: searching for text '%s' from %d to %d origin %d", LCSTR(pattern), start, end, origin ); if ( doc->text_view->getDocument()->findText( pattern, caseInsensitive, reverse, start, end, words, 200, pageHeight ) ) { CRLog::debug("CRViewDialog::findText: pattern found"); doc->text_view->clearSelection(); doc->text_view->selectWords( words ); ldomMarkedRangeList * ranges = doc->text_view->getMarkedRanges(); if ( ranges && ranges->length() > 0 ) { lua_newtable(L); // hold all words for (int i = 0; i < words.length(); i++) { ldomWord word = words[i]; lua_newtable(L); // new word lua_pushstring(L, "start"); lua_pushstring(L, UnicodeToLocal(word.getStartXPointer().toString()).c_str()); lua_settable(L, -3); lua_pushstring(L, "end"); lua_pushstring(L, UnicodeToLocal(word.getEndXPointer().toString()).c_str()); lua_settable(L, -3); lua_rawseti(L, -2, i + 1); } return 1; } } CRLog::debug("CRViewDialog::findText: pattern not found"); return 0; }
static int getWordBoxesFromPositions(lua_State *L) { CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); const char* pos0 = luaL_checkstring(L, 2); const char* pos1 = luaL_checkstring(L, 3); LVDocView *tv = doc->text_view; ldomDocument *dv = doc->dom_doc; ldomXPointer startp = dv->createXPointer(lString16(pos0)); ldomXPointer endp = dv->createXPointer(lString16(pos1)); lua_newtable(L); // new word boxes if (!startp.isNull() && !endp.isNull()) { ldomXRange r(startp, endp); if (r.getStart().isNull() || r.getEnd().isNull()) return 0; r.sort(); if (!r.getStart().isVisibleWordStart()) r.getStart().prevVisibleWordStart(); if (!r.getEnd().isVisibleWordEnd()) r.getEnd().nextVisibleWordEnd(); if (r.isNull()) return 0; r.setFlags(1); //tv->selectRange(r); // we don't need native highlight of selection /* accumulate text lines */ LVArray<ldomWord> words; r.getRangeWords(words); lvRect charRect, wordRect, lineRect; int lcount = 1; int lastx = -1; lua_newtable(L); // first line box for (int i=0; i<words.length(); i++) { if (ldomXRange(words[i]).getRectEx(wordRect)) { if (!docToWindowRect(tv, wordRect)) continue;//docToWindowRect returns false means it is not on current showing page. if (wordRect.left < lastx) { lua_pushLineRect(L, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom, lcount++); lua_newtable(L); // new line box lineRect.clear(); } lineRect.extend(wordRect); lastx = wordRect.left; } else { // word is hyphenated ldomWord word = words[i]; int y = -1; for (int j=word.getStart(); j < word.getEnd(); j++) { if (ldomXPointer(word.getNode(), j).getRectEx(charRect)) { if (!docToWindowRect(tv, charRect)) continue; if (y == -1) y = charRect.top; if (j != word.getStart() && y == charRect.top) continue; y = charRect.top; if (charRect.left < lastx) { lua_pushLineRect(L, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom, lcount++); lua_newtable(L); // new line box lineRect.clear(); } lineRect.extend(charRect); lastx = charRect.left; } } } } lua_pushLineRect(L, lineRect.left, lineRect.top, lineRect.right, lineRect.bottom, lcount); } return 1; }