diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 750e1259c..a6803b86c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ name: CI -on: push +on: [push, pull_request] jobs: linux: diff --git a/crengine/include/lvdocview.h b/crengine/include/lvdocview.h index f1a3865f3..1f7bc445c 100644 --- a/crengine/include/lvdocview.h +++ b/crengine/include/lvdocview.h @@ -389,14 +389,6 @@ class LVDocView : public CacheLoadingCallback void updateDocStyleSheet(); protected: - - - virtual void drawNavigationBar( LVDrawBuf * drawbuf, int pageIndex, int percent ); - - virtual void getNavigationBarRectangle( lvRect & rc ); - - virtual void getNavigationBarRectangle( int pageIndex, lvRect & rc ); - /// returns document offset for next page int getNextPageOffset(); /// returns document offset for previous page @@ -993,6 +985,6 @@ class SimpleTitleFormatter { /// draw book cover, either from image, or generated from title/authors -void LVDrawBookCover(LVDrawBuf & buf, LVImageSourceRef image, lString8 fontFace, lString32 title, lString32 authors, lString32 seriesName, int seriesNumber); +void LVDrawBookCover(LVDrawBuf & buf, LVImageSourceRef image, bool respectAspectRatio, lString8 fontFace, lString32 title, lString32 authors, lString32 seriesName, int seriesNumber); #endif diff --git a/crengine/include/lvhashtable.h b/crengine/include/lvhashtable.h index 75904ea72..c83eb4910 100644 --- a/crengine/include/lvhashtable.h +++ b/crengine/include/lvhashtable.h @@ -217,6 +217,11 @@ template class LVHashTable } return false; } + void compact() + { + if (_count > 0 && _count < _size) + resize(_count); + } private: int _size; int _count; diff --git a/crengine/include/lvstring.h b/crengine/include/lvstring.h index d46584cef..c79328c30 100644 --- a/crengine/include/lvstring.h +++ b/crengine/include/lvstring.h @@ -329,6 +329,8 @@ class lString8 lString8 & replace(size_type p0, size_type n0, const lString8 & str, size_type offset, size_type count); /// replace fragment with repeated character lString8 & replace(size_type p0, size_type n0, size_type count, value_type ch); + /// replaces every occurrence of the character before with the character after and returns a reference to this string + lString8 & replace(value_type before, value_type after); /// make string uppercase lString8 & uppercase(); /// make string lowercase @@ -700,6 +702,10 @@ class lString32 bool atoi( int &n ) const; /// converts to 64 bit integer, returns true if success bool atoi( lInt64 &n ) const; + /// convert to double + double atod() const; + /// convert to double, returns true if success + bool atod( double &d, char dp = '.' ) const; /// returns constant c-string pointer const value_type * c_str() const { return pchunk->buf32; } /// returns constant c-string pointer, same as c_str() diff --git a/crengine/include/lvtinydom.h b/crengine/include/lvtinydom.h index 2853a0ee3..bf6290d2d 100644 --- a/crengine/include/lvtinydom.h +++ b/crengine/include/lvtinydom.h @@ -1781,15 +1781,15 @@ class ldomXPointerEx : public ldomXPointer bool nextVisibleWordEnd( bool thisBlockOnly = false ); /// move to previous visible word beginning (in sentence) - bool prevVisibleWordStartInSentence(); + bool prevVisibleWordStartInSentence(bool thisBlockOnly); /// move to previous visible word end (in sentence) - bool prevVisibleWordEndInSentence(); + bool prevVisibleWordEndInSentence(bool thisBlockOnly); /// move to next visible word beginning (in sentence) - bool nextVisibleWordStartInSentence(); + bool nextVisibleWordStartInSentence(bool thisBlockOnly); /// move to end of current word (in sentence) bool thisVisibleWordEndInSentence(); /// move to next visible word end (in sentence) - bool nextVisibleWordEndInSentence(); + bool nextVisibleWordEndInSentence(bool thisBlockOnly); /// move to beginning of current visible text sentence bool thisSentenceStart(); diff --git a/crengine/src/chmfmt.cpp b/crengine/src/chmfmt.cpp index 583ee8cc0..1f4f23f64 100644 --- a/crengine/src/chmfmt.cpp +++ b/crengine/src/chmfmt.cpp @@ -5,6 +5,10 @@ #include "../include/chmfmt.h" #include +#include "../include/fb2def.h" +#define XS_IMPLEMENT_SCHEME 1 +#include "../include/fb2def.h" + #define DUMP_CHM_DOC 0 struct crChmExternalFileStream : public chmExternalFileStream { @@ -819,7 +823,7 @@ class CHMSystem { } lString32 getContentsFileName() { - if ( _binaryTOCURLTableId!=0 ) { + if ( _binaryTOCURLTableId!=0 && _urlTable != NULL ) { lString8 url = _urlTable->urlById(_binaryTOCURLTableId); if ( !url.empty() ) return decodeString(url); @@ -860,10 +864,10 @@ ldomDocument * LVParseCHMHTMLStream( LVStreamRef stream, lString32 defEncodingNa if ( stream.isNull() ) return NULL; +#if 0 // detect encondig stream->SetPos(0); -#if 0 ldomDocument * encDetectionDoc = LVParseHTMLStream( stream ); int encoding = 0; if ( encDetectionDoc!=NULL ) { @@ -899,11 +903,14 @@ ldomDocument * LVParseCHMHTMLStream( LVStreamRef stream, lString32 defEncodingNa ldomDocument * doc; doc = new ldomDocument(); doc->setDocFlags( 0 ); + doc->setNodeTypes(fb2_elem_table); + doc->setAttributeTypes(fb2_attr_table); + doc->setNameSpaceTypes(fb2_ns_table); ldomDocumentWriterFilter writerFilter(doc, false, HTML_AUTOCLOSE_TABLE); writerFilter.setFlags(writerFilter.getFlags() | TXTFLG_CONVERT_8BIT_ENTITY_ENCODING); - /// FB2 format + /// HTML format LVFileFormatParser * parser = new LVHTMLParser(stream, &writerFilter); if ( !defEncodingName.empty() ) parser->SetCharset(defEncodingName.c_str()); @@ -1103,11 +1110,11 @@ class CHMTOCReader { return false; } - #if DUMP_CHM_DOC==1 - LVStreamRef out = LVOpenFileStream(U"/tmp/chm-toc.html", LVOM_WRITE); - if ( !out.isNull() ) - doc->saveToStream( out, NULL, true ); - #endif +#if DUMP_CHM_DOC==1 + LVStreamRef out = LVOpenFileStream(U"chm-toc.xml", LVOM_WRITE); + if ( !out.isNull() ) + doc->saveToStream( out, NULL, true ); +#endif ldomNode * body = doc->getRootNode(); //doc->createXPointer(cs32("/html[1]/body[1]")); bool res = false; diff --git a/crengine/src/lvdocview.cpp b/crengine/src/lvdocview.cpp index 19ee19fb8..51894793a 100644 --- a/crengine/src/lvdocview.cpp +++ b/crengine/src/lvdocview.cpp @@ -1648,31 +1648,6 @@ void LVDocView::getPageRectangle(int pageIndex, lvRect & pageRect, bool mergeTwo } } -void LVDocView::getNavigationBarRectangle(lvRect & navRect) { - getNavigationBarRectangle(getVisiblePageCount() == 2 ? 1 : 2, navRect); -} - -void LVDocView::getNavigationBarRectangle(int pageIndex, lvRect & navRect) { - lvRect headerRect; - getPageHeaderRectangle(pageIndex, headerRect); - navRect = headerRect; - if (headerRect.bottom <= headerRect.top) - return; - navRect.top = navRect.bottom - 6; -} - -void LVDocView::drawNavigationBar(LVDrawBuf * drawbuf, int pageIndex, - int percent) { - CR_UNUSED2(drawbuf, percent); - //LVArray & sbounds = getSectionBounds(); - lvRect navBar; - getNavigationBarRectangle(pageIndex, navBar); - //bool leftPage = (getVisiblePageCount()==2 && !(pageIndex&1) ); - - //lUInt32 cl1 = 0xA0A0A0; - //lUInt32 cl2 = getBackgroundColor(); -} - /// sets battery state bool LVDocView::setBatteryState(int newState) { if (m_battery_state == newState) @@ -1736,9 +1711,6 @@ void LVDocView::drawPageHeader(LVDrawBuf * drawbuf, const lvRect & headerRc, int percent_pos = /*info.left + */percent * info.width() / 10000; // int gh = 3; //drawGauge ? 3 : 1; LVArray & sbounds = getSectionBounds(); - // NavBar no longer used: - // lvRect navBar; - // getNavigationBarRectangle(pageIndex, navBar); int gpos = info.bottom; // if (drawbuf->GetBitsPerPixel() <= 2) { // // gray @@ -6475,10 +6447,14 @@ CRPropRef LVDocView::propsApply(CRPropRef props) { } else if (name == PROP_FONT_GAMMA) { double gamma = 1.0; lString32 s = props->getStringDef(PROP_FONT_GAMMA, "1.0"); - lString8 s8 = UnicodeToUtf8(s); - if ( sscanf(s8.c_str(), "%lf", &gamma)==1 ) { + // When parsing a gamma value string, the decimal point is always '.' char. + // So if a different decimal point character is used in the current locale, + // and if we use some library function to convert the string to floating point number, then it may fail. + if (s.atod(gamma, '.')) { fontMan->SetGamma(gamma); clearImageCache(); + } else { + CRLog::error("Invalid gamma value (%s)", LCSTR(s)); } } else if (name == PROP_FONT_HINTING) { int mode = props->getIntDef(PROP_FONT_HINTING, (int)HINTING_MODE_AUTOHINT); @@ -7042,7 +7018,7 @@ static cover_palette_t series_palette[8] = { {0x00C0D0C0, 0x20E8E8D8, 0xC0FFC040, 0xD0F0E0E0, 0x00400040, 0x00000080, 0x00402040, 0x80FFFFFF}, }; -void LVDrawBookCover(LVDrawBuf & buf, LVImageSourceRef image, lString8 fontFace, lString32 title, lString32 authors, lString32 seriesName, int seriesNumber) { +void LVDrawBookCover(LVDrawBuf & buf, LVImageSourceRef image, bool respectAspectRatio, lString8 fontFace, lString32 title, lString32 authors, lString32 seriesName, int seriesNumber) { CR_UNUSED(seriesNumber); bool isGray = buf.GetBitsPerPixel() <= 8; cover_palette_t * palette = NULL; @@ -7057,8 +7033,24 @@ void LVDrawBookCover(LVDrawBuf & buf, LVImageSourceRef image, lString8 fontFace, int dx = buf.GetWidth(); int dy = buf.GetHeight(); if (!image.isNull() && image->GetWidth() > 0 && image->GetHeight() > 0) { + int xoff = 0; + int yoff = 0; + if (respectAspectRatio) { + // recalc dx, dy for respectAspectRatio + int dst_aspect = 100*dx/dy; + int src_aspect = 100*image->GetWidth()/image->GetHeight(); + if (dst_aspect > src_aspect) { + int new_dx = src_aspect*dy/100; + xoff = (dx - new_dx + 1)/2; + dx = new_dx; + } else if (dst_aspect < src_aspect) { + int new_dy = 100*dx/src_aspect; + yoff = (dy - new_dy + 1)/2; + dy = new_dy; + } + } CRLog::trace("drawing image cover page %d x %d", dx, dy); - buf.Draw(image, 0, 0, dx, dy); + buf.Draw(image, xoff, yoff, dx, dy); return; } diff --git a/crengine/src/lvfntman.cpp b/crengine/src/lvfntman.cpp index d05cf0911..503f559ac 100644 --- a/crengine/src/lvfntman.cpp +++ b/crengine/src/lvfntman.cpp @@ -354,6 +354,11 @@ static lChar32 getReplacementChar(lUInt32 code, bool * can_be_ignored = NULL) { case 0x25AA: // css_lst_square: case 0x25FE: // css_lst_square: return '-'; + case 0x21AF: // DOWNWARDS ZIGZAG ARROW + case 0x26A1: // HIGH VOLTAGE SIGN + case 0x2B4D: // DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW + case 0x1F5F2:// LIGHTNING MOOD + return '+'; default: break; } @@ -2209,7 +2214,7 @@ class LVFreeTypeFace : public LVFont lUInt16 prev_width = 0; lUInt16 cur_width = 0; - int lastFitChar = 0; + lUInt16 lastFitChar = 0; updateTransform(); // no-op // measure character widths @@ -2423,17 +2428,22 @@ class LVFreeTypeFace : public LVFont fb_hints &= ~LFNT_HINT_BEGINS_PARAGRAPH; if ( t_notdef_end < len ) fb_hints &= ~LFNT_HINT_ENDS_PARAGRAPH; - fallback->measureText( text + t_notdef_start, t_notdef_end - t_notdef_start, + lUInt16 last_good_width = t_notdef_start > 0 ? widths[t_notdef_start-1] : 0; + lUInt16 chars_measured = fallback->measureText( text + t_notdef_start, t_notdef_end - t_notdef_start, widths + t_notdef_start, flags + t_notdef_start, - max_width, def_char, lang_cfg, letter_spacing, allow_hyphenation, + max_width - last_good_width, def_char, lang_cfg, letter_spacing, allow_hyphenation, fb_hints ); + lastFitChar = t_notdef_start + chars_measured; // Fix previous bad measurements - int last_good_width = t_notdef_start > 0 ? widths[t_notdef_start-1] : 0; - for (int tn = t_notdef_start; tn < t_notdef_end; tn++) { + for (int tn = t_notdef_start; tn < lastFitChar; tn++) { widths[tn] += last_good_width; + if (widths[tn] > max_width) { + lastFitChar = tn; + break; + } } // And fix our current width - cur_width = widths[t_notdef_end-1]; + cur_width = widths[lastFitChar-1]; prev_width = cur_width; #ifdef DEBUG_MEASURE_TEXT printf("MTHB ### measured past failures > W= %d\n[...]", cur_width); @@ -2524,18 +2534,22 @@ class LVFreeTypeFace : public LVFont lUInt32 fb_hints = hints | LFNT_HINT_IS_FALLBACK_FONT; if ( t_notdef_start > 0 ) fb_hints &= ~LFNT_HINT_BEGINS_PARAGRAPH; - int chars_measured = fallback->measureText( text + t_notdef_start, // start + lUInt16 last_good_width = t_notdef_start > 0 ? widths[t_notdef_start-1] : 0; + lUInt16 chars_measured = fallback->measureText( text + t_notdef_start, // start t_notdef_end - t_notdef_start, // len widths + t_notdef_start, flags + t_notdef_start, - max_width, def_char, lang_cfg, letter_spacing, allow_hyphenation, + max_width - last_good_width, def_char, lang_cfg, letter_spacing, allow_hyphenation, fb_hints ); lastFitChar = t_notdef_start + chars_measured; - int last_good_width = t_notdef_start > 0 ? widths[t_notdef_start-1] : 0; - for (int tn = t_notdef_start; tn < t_notdef_end; tn++) { + for (int tn = t_notdef_start; tn < lastFitChar; tn++) { widths[tn] += last_good_width; + if (widths[tn] > max_width) { + lastFitChar = tn; + break; + } } // And add all that to our current width - cur_width = widths[t_notdef_end-1]; + cur_width = widths[lastFitChar-1]; #ifdef DEBUG_MEASURE_TEXT printf("MTHB ### measured past failures at EOT > W= %d\n[...]", cur_width); #endif @@ -2548,7 +2562,7 @@ class LVFreeTypeFace : public LVFont } // i is used below to "fill props for rest of chars", so make it accurate - i = len; // actually make it do nothing + i = lastFitChar; #ifdef DEBUG_MEASURE_TEXT printf("MTHB <<< W=%d [%s]\n", cur_width, _faceName.c_str()); diff --git a/crengine/src/lvstring.cpp b/crengine/src/lvstring.cpp index 8e3ca78e4..d3be13ad3 100644 --- a/crengine/src/lvstring.cpp +++ b/crengine/src/lvstring.cpp @@ -1241,6 +1241,88 @@ bool lString32::atoi( lInt64 &n ) const return *s=='\0' || *s==' ' || *s=='\t'; } +double lString32::atod() const { + double d = 0.0; + bool res = atod(d, '.'); + return res ? d : 0.0; +} + +bool lString32::atod( double &d, char dp ) const { + // Simplified implementation without overflow checking + int sign = 1; + unsigned long intg = 0; + unsigned long frac = 0; + unsigned long frac_div = 1; + unsigned int exp = 0; + int exp_sign = 1; + bool res = false; + const value_type * s = c_str(); + while (*s == ' ' || *s == '\t') + s++; + if (*s == '-') { + sign = -1; + s++; + } + else if (*s == '+') { + s++; + } + if (*s>='0' && *s<='9') { + res = true; + while (*s>='0' && *s<='9') { + intg = intg * 10 + ( (*s)-'0' ); + s++; + } + } + if (res && *s == dp) { + // decimal point found + s++; + res = false; + if (*s>='0' && *s<='9') { + res = true; + while (*s>='0' && *s<='9') { + frac = frac * 10 + ( (*s)-'0' ); + s++; + frac_div *= 10; + } + } + } + if (res && (*s == 'e' || *s == 'E')) { + // exponent part + s++; + if (*s == '-') { + exp_sign = -1; + s++; + } + else if (*s == '+') { + s++; + } + res = false; + if (*s>='0' && *s<='9') { + res = true; + while (*s>='0' && *s<='9') { + exp = exp * 10 + ( (*s)-'0' ); + s++; + } + } + } + if (res && (*s != '\0' && *s != ' ' && *s != '\t')) { + // unprocessed characters left + res = false; + } + d = (double)intg; + if (frac_div > 1) + d += ((double)frac)/((double)frac_div); + if (exp > 1) { + double pwr = exp_sign > 0 ? 10.0 : 0.1; + for (unsigned int i = 0; i < exp; i++) { + d *= pwr; + } + } + if (sign < 0) + d = -d; + return res; +} + #define STRING_HASH_MULT 31 lUInt32 lString32::getHash() const { @@ -5199,6 +5281,16 @@ lString8 & lString8::replace(size_type p0, size_type n0, const lString8 & str) { return *this; } +lString8 & lString8::replace(value_type before, value_type after) { + value_type* ptr = modify(); + while (*ptr) { + if (*ptr == before) + *ptr = after; + ++ptr; + } + return *this; +} + lString32 & lString32::replace(size_type p0, size_type n0, const lString32 & str) { lString32 s1 = substr( 0, p0 ); diff --git a/crengine/src/lvtinydom.cpp b/crengine/src/lvtinydom.cpp index dcfb008f3..9a32465b0 100644 --- a/crengine/src/lvtinydom.cpp +++ b/crengine/src/lvtinydom.cpp @@ -12325,7 +12325,7 @@ bool ldomXPointerEx::nextVisibleWordEnd( bool thisBlockOnly ) } /// move to previous visible word beginning (in sentence) -bool ldomXPointerEx::prevVisibleWordStartInSentence() +bool ldomXPointerEx::prevVisibleWordStartInSentence(bool thisBlockOnly) { if ( isNull() ) return false; @@ -12334,7 +12334,7 @@ bool ldomXPointerEx::prevVisibleWordStartInSentence() for ( ;; ) { if ( !isText() || !isVisible() || _data->getOffset()==0 ) { // move to previous text - if ( !prevVisibleText(false) ) + if ( !prevVisibleText(thisBlockOnly) ) return false; node = getNode(); text = node->getText(); @@ -12361,7 +12361,7 @@ bool ldomXPointerEx::prevVisibleWordStartInSentence() } /// move to next visible word beginning (in sentence) -bool ldomXPointerEx::nextVisibleWordStartInSentence() +bool ldomXPointerEx::nextVisibleWordStartInSentence(bool thisBlockOnly) { if ( isNull() ) return false; @@ -12372,7 +12372,7 @@ bool ldomXPointerEx::nextVisibleWordStartInSentence() for ( ;; ) { if ( !isText() || !isVisible() ) { // move to next text - if ( !nextVisibleText(false) ) + if ( !nextVisibleText(thisBlockOnly) ) return false; node = getNode(); text = node->getText(); @@ -12386,7 +12386,7 @@ bool ldomXPointerEx::nextVisibleWordStartInSentence() textLen = text.length(); if ( _data->getOffset() < textLen ) break; - if ( !nextVisibleText(false) ) + if ( !nextVisibleText(thisBlockOnly) ) return false; _data->setOffset( 0 ); moved = true; @@ -12450,7 +12450,7 @@ bool ldomXPointerEx::thisVisibleWordEndInSentence() } /// move to next visible word end (in sentence) -bool ldomXPointerEx::nextVisibleWordEndInSentence() +bool ldomXPointerEx::nextVisibleWordEndInSentence(bool thisBlockOnly) { if ( isNull() ) return false; @@ -12461,7 +12461,7 @@ bool ldomXPointerEx::nextVisibleWordEndInSentence() for ( ;; ) { if ( !isText() || !isVisible() ) { // move to previous text - if ( !nextVisibleText(true) ) + if ( !nextVisibleText(thisBlockOnly) ) return false; node = getNode(); text = node->getText(); @@ -12475,7 +12475,7 @@ bool ldomXPointerEx::nextVisibleWordEndInSentence() textLen = text.length(); if ( _data->getOffset() < textLen ) break; - if ( !nextVisibleText(true) ) + if ( !nextVisibleText(thisBlockOnly) ) return false; _data->setOffset( 0 ); } @@ -12512,7 +12512,7 @@ bool ldomXPointerEx::nextVisibleWordEndInSentence() } /// move to previous visible word end (in sentence) -bool ldomXPointerEx::prevVisibleWordEndInSentence() +bool ldomXPointerEx::prevVisibleWordEndInSentence(bool thisBlockOnly) { if ( isNull() ) return false; @@ -12522,7 +12522,7 @@ bool ldomXPointerEx::prevVisibleWordEndInSentence() for ( ;; ) { if ( !isText() || !isVisible() || _data->getOffset()==0 ) { // move to previous text - if ( !prevVisibleText(false) ) + if ( !prevVisibleText(thisBlockOnly) ) return false; node = getNode(); text = node->getText(); @@ -12676,16 +12676,26 @@ bool ldomXPointerEx::isSentenceStart() int i = _data->getOffset(); lChar32 currCh = i0 ? text[i-1] : 0; + lChar32 prevPrevNonSpace = 0; lChar32 prevNonSpace = 0; + int prevNonSpace_i = -1; for ( ;i>0; i-- ) { lChar32 ch = text[i-1]; if ( !IsUnicodeSpace(ch) ) { prevNonSpace = ch; + prevNonSpace_i = i - 1; break; } } -#if 0 - // At this implementation it's a wrong to check previous node + if (prevNonSpace) { + for (i = prevNonSpace_i; i>0; i-- ) { + lChar32 ch = text[i-1]; + if ( !IsUnicodeSpace(ch) ) { + prevPrevNonSpace = ch; + break; + } + } + } if ( !prevNonSpace ) { ldomXPointerEx pos(*this); while ( !prevNonSpace && pos.prevVisibleText(true) ) { @@ -12694,12 +12704,18 @@ bool ldomXPointerEx::isSentenceStart() lChar32 ch = prevText[j]; if ( !IsUnicodeSpace(ch) ) { prevNonSpace = ch; + for (int k = j; k > 0; k--) { + ch = prevText[k-1]; + if (!IsUnicodeSpace(ch)) { + prevPrevNonSpace = ch; + break; + } + } break; } } } } -#endif // skip separated separator. if (1 == textLen) { @@ -12707,7 +12723,7 @@ bool ldomXPointerEx::isSentenceStart() case '.': case '?': case '!': - case U'\x2026': // horizontal ellypsis + case U'\x2026': // horizontal ellipsis return false; } } @@ -12718,8 +12734,18 @@ bool ldomXPointerEx::isSentenceStart() case '.': case '?': case '!': - case U'\x2026': // horizontal ellypsis + case U'\x2026': // horizontal ellipsis return true; + case '"': // QUOTATION MARK + case U'\x201d': // RIGHT DOUBLE QUOTATION MARK + switch (prevPrevNonSpace) { + case '.': + case '?': + case '!': + case U'\x2026': // horizontal ellipsis + return true; + } + break; default: return false; } @@ -12740,14 +12766,25 @@ bool ldomXPointerEx::isSentenceEnd() int i = _data->getOffset(); lChar32 currCh = i0 ? text[i-1] : 0; + lChar32 prevPrevCh = i>1 ? text[i-2] : 0; if ( IsUnicodeSpaceOrNull(currCh) ) { switch (prevCh) { case 0: case '.': case '?': case '!': - case U'\x2026': // horizontal ellypsis + case U'\x2026': // horizontal ellipsis return true; + case '"': + case U'\x201d': // RIGHT DOUBLE QUOTATION MARK + switch (prevPrevCh) { + case '.': + case '?': + case '!': + case U'\x2026': // horizontal ellipsis + return true; + } + break; default: break; } @@ -12755,8 +12792,8 @@ bool ldomXPointerEx::isSentenceEnd() // word is not ended with . ! ? // check whether it's last word of block ldomXPointerEx pos(*this); - //return !pos.nextVisibleWordStartInSentence(); - return !pos.thisVisibleWordEndInSentence(); + return !pos.nextVisibleWordStartInSentence(false); + //return !pos.thisVisibleWordEndInSentence(); } /// move to beginning of current visible text sentence @@ -12769,7 +12806,7 @@ bool ldomXPointerEx::thisSentenceStart() for (;;) { if ( isSentenceStart() ) return true; - if ( !prevVisibleWordStartInSentence() ) + if ( !prevVisibleWordStartInSentence(true) ) return false; } } @@ -12784,7 +12821,7 @@ bool ldomXPointerEx::thisSentenceEnd() for (;;) { if ( isSentenceEnd() ) return true; - if ( !nextVisibleWordEndInSentence() ) + if ( !nextVisibleWordEndInSentence(true) ) return false; } } @@ -12795,7 +12832,7 @@ bool ldomXPointerEx::nextSentenceStart() if ( !isSentenceStart() && !thisSentenceEnd() ) return false; for (;;) { - if ( !nextVisibleWordStartInSentence() ) + if ( !nextVisibleWordStartInSentence(false) ) return false; if ( isSentenceStart() ) return true; @@ -12808,7 +12845,7 @@ bool ldomXPointerEx::prevSentenceStart() if ( !thisSentenceStart() ) return false; for (;;) { - if ( !prevVisibleWordStartInSentence() ) + if ( !prevVisibleWordStartInSentence(false) ) return false; if ( isSentenceStart() ) return true; @@ -12829,7 +12866,7 @@ bool ldomXPointerEx::prevSentenceEnd() if ( !thisSentenceStart() ) return false; for (;;) { - if ( !prevVisibleWordEndInSentence() ) + if ( !prevVisibleWordEndInSentence(false) ) return false; if ( isSentenceEnd() ) return true; diff --git a/thirdparty/chmlib/src/lzx.c b/thirdparty/chmlib/src/lzx.c index 700e317a8..dc8d6f9bb 100644 --- a/thirdparty/chmlib/src/lzx.c +++ b/thirdparty/chmlib/src/lzx.c @@ -268,7 +268,7 @@ int LZXreset(struct LZXstate *pState) #define ENSURE_BITS(n) \ while (bitsleft < (n)) { \ - bitbuf |= ((inpos[1]<<8)|inpos[0]) << (ULONG_BITS-16 - bitsleft); \ + bitbuf |= (ULONG)((inpos[1]<<8)|inpos[0]) << (ULONG_BITS-16 - bitsleft); \ bitsleft += 16; inpos+=2; \ }