diff --git a/crengine/include/cssdef.h b/crengine/include/cssdef.h index 71c740a25..719f7cb43 100644 --- a/crengine/include/cssdef.h +++ b/crengine/include/cssdef.h @@ -260,14 +260,6 @@ enum css_background_repeat_value_t { css_background_r_inherit, css_background_r_none }; -enum css_background_attachment_value_t { - css_background_scroll, - css_background_fixed, - css_background_local, - css_background_a_initial, - css_background_a_inherit, - css_background_a_none -}; enum css_background_position_value_t { css_background_left_top, css_background_left_center, @@ -330,9 +322,11 @@ enum css_direction_t { }; enum css_generic_value_t { - css_generic_auto = -1, // (css_val_unspecified, css_generic_auto), for "margin: auto" - css_generic_normal = -2, // (css_val_unspecified, css_generic_normal), for "line-height: normal" - css_generic_transparent = -3 // (css_val_unspecified, css_generic_transparent), for "color: transparent" + css_generic_auto = -1, // (css_val_unspecified, css_generic_auto), for "margin: auto" + css_generic_normal = -2, // (css_val_unspecified, css_generic_normal), for "line-height: normal" + css_generic_transparent = -3, // (css_val_unspecified, css_generic_transparent), for "color: transparent" + css_generic_contain = -4, // (css_val_unspecified, css_generic_contain), for "background-size: contain" + css_generic_cover = -5 // (css_val_unspecified, css_generic_cover), for "background-size: cover" }; // Non standard property for providing hints to crengine via style tweaks diff --git a/crengine/include/dtddef.h b/crengine/include/dtddef.h index 2e6856e20..c9ee348fc 100644 --- a/crengine/include/dtddef.h +++ b/crengine/include/dtddef.h @@ -125,25 +125,25 @@ struct ns_def_t { #define XS_BEGIN_TAGS \ static elem_def_t fb2_elem_table [] = { #define XS_TAG1(itm) \ - { el_ ## itm, #itm, {false, false, css_d_block, css_ws_normal} }, + { el_ ## itm, #itm, {false, false, css_d_block, css_ws_inherit} }, #define XS_TAG2(itm, name) \ - { el_ ## itm, name, {false, false, css_d_block, css_ws_normal} }, + { el_ ## itm, name, {false, false, css_d_block, css_ws_inherit} }, #define XS_TAG1T(itm) \ - { el_ ## itm, #itm, {true, false, css_d_block, css_ws_normal} }, + { el_ ## itm, #itm, {true, false, css_d_block, css_ws_inherit} }, #define XS_TAG1OBJ(itm) \ - { el_ ## itm, #itm, {false, true, css_d_inline, css_ws_normal} }, + { el_ ## itm, #itm, {false, true, css_d_inline, css_ws_inherit} }, #define XS_TAG2T(itm, name) \ - { el_ ## itm, name, {true, false, css_d_block, css_ws_normal} }, + { el_ ## itm, name, {true, false, css_d_block, css_ws_inherit} }, #define XS_TAG1I(itm) \ - { el_ ## itm, #itm, {true, false, css_d_inline, css_ws_normal} }, + { el_ ## itm, #itm, {true, false, css_d_inline, css_ws_inherit} }, #define XS_TAG2I(itm, name) \ - { el_ ## itm, name, {true, false, css_d_inline, css_ws_normal} }, + { el_ ## itm, name, {true, false, css_d_inline, css_ws_inherit} }, #define XS_TAG1D(itm, txt, disp, ws) \ { el_ ## itm, #itm, {txt, false, disp, ws} }, #define XS_TAG2D(itm, name, txt, false, disp, ws) \ { el_ ## itm, name, {txt, false, disp, ws} }, #define XS_END_TAGS \ - { 0, NULL, {false, false, css_d_block, css_ws_normal} } \ + { 0, NULL, {false, false, css_d_block, css_ws_inherit} } \ }; #undef XS_BEGIN_ATTRS diff --git a/crengine/include/fb2def.h b/crengine/include/fb2def.h index f17ba5629..db5741035 100644 --- a/crengine/include/fb2def.h +++ b/crengine/include/fb2def.h @@ -48,7 +48,7 @@ XS_TAG1I( inlineBox ) // - it doesn't have a text node child, the content will be fetched from // its style->content when rendering and drawing text. // It does not box anything and has no child, so it's not considered a boxing node. -XS_TAG1D( pseudoElem, false, css_d_none, css_ws_normal ) +XS_TAG1D( pseudoElem, false, css_d_none, css_ws_inherit ) // Internal element for EPUB, containing each individual HTML file XS_TAG1( DocFragment ) @@ -59,10 +59,10 @@ XS_TAG2( xml_stylesheet, "?xml-stylesheet" ) // Classic HTML / EPUB elements XS_TAG1( html ) XS_TAG1( head ) -XS_TAG1D( title, true, css_d_block, css_ws_normal ) -XS_TAG1D( style, true, css_d_none, css_ws_normal ) -XS_TAG1D( script, true, css_d_none, css_ws_normal ) -XS_TAG1D( base, false, css_d_none, css_ws_normal ) // among crengine autoclose elements +XS_TAG1D( title, true, css_d_block, css_ws_inherit ) +XS_TAG1D( style, true, css_d_none, css_ws_inherit ) +XS_TAG1D( script, true, css_d_none, css_ws_inherit ) +XS_TAG1D( base, false, css_d_none, css_ws_inherit ) // among crengine autoclose elements XS_TAG1T( body ) XS_TAG1( param ) /* quite obsolete, child of ... was there, let's keep it */ @@ -123,16 +123,16 @@ XS_TAG1T( dt ) XS_TAG1T( dd ) // Tables -XS_TAG1D( table, false, css_d_table, css_ws_normal ) -XS_TAG1D( caption, true, css_d_table_caption, css_ws_normal ) -XS_TAG1D( col, false, css_d_table_column, css_ws_normal ) -XS_TAG1D( colgroup, false, css_d_table_column_group, css_ws_normal ) -XS_TAG1D( tr, false, css_d_table_row, css_ws_normal ) -XS_TAG1D( tbody, false, css_d_table_row_group, css_ws_normal ) -XS_TAG1D( thead, false, css_d_table_header_group, css_ws_normal ) -XS_TAG1D( tfoot, false, css_d_table_footer_group, css_ws_normal ) -XS_TAG1D( th, true, css_d_table_cell, css_ws_normal ) -XS_TAG1D( td, true, css_d_table_cell, css_ws_normal ) +XS_TAG1D( table, false, css_d_table, css_ws_inherit ) +XS_TAG1D( caption, true, css_d_table_caption, css_ws_inherit ) +XS_TAG1D( col, false, css_d_table_column, css_ws_inherit ) +XS_TAG1D( colgroup, false, css_d_table_column_group, css_ws_inherit ) +XS_TAG1D( tr, false, css_d_table_row, css_ws_inherit ) +XS_TAG1D( tbody, false, css_d_table_row_group, css_ws_inherit ) +XS_TAG1D( thead, false, css_d_table_header_group, css_ws_inherit ) +XS_TAG1D( tfoot, false, css_d_table_footer_group, css_ws_inherit ) +XS_TAG1D( th, true, css_d_table_cell, css_ws_inherit ) +XS_TAG1D( td, true, css_d_table_cell, css_ws_inherit ) // Inline elements XS_TAG1OBJ( img ) /* inline and specific handling as 'object' */ @@ -168,7 +168,7 @@ XS_TAG1I( u ) XS_TAG1I( var ) // Ruby elements (defaults to inline) -XS_TAG1D( ruby, true, css_d_ruby, css_ws_normal ) +XS_TAG1D( ruby, true, css_d_ruby, css_ws_inherit ) XS_TAG1I( rbc ) // no more in HTML5, but in 2001's https://www.w3.org/TR/ruby/ XS_TAG1I( rtc ) XS_TAG1I( rb ) @@ -189,10 +189,10 @@ XS_TAG1( epigraph ) XS_TAG1( part ) XS_TAG1( poem ) XS_TAG1( stanza ) -XS_TAG1D( binary, true, css_d_none, css_ws_normal ) -XS_TAG1D( description, false, css_d_none, css_ws_normal ) -XS_TAG1D( genre, true, css_d_none, css_ws_normal ) -XS_TAG1D( stylesheet, true, css_d_none, css_ws_normal ) +XS_TAG1D( binary, true, css_d_none, css_ws_inherit ) +XS_TAG1D( description, false, css_d_none, css_ws_inherit ) +XS_TAG1D( genre, true, css_d_none, css_ws_inherit ) +XS_TAG1D( stylesheet, true, css_d_none, css_ws_inherit ) XS_TAG1I( spacing ) XS_TAG1I( strikethrough ) XS_TAG1I( underline ) diff --git a/crengine/include/hyphman.h b/crengine/include/hyphman.h index 318e46e15..e542d471e 100644 --- a/crengine/include/hyphman.h +++ b/crengine/include/hyphman.h @@ -74,12 +74,12 @@ class HyphDictionary public: HyphDictionary( HyphDictType type, lString16 title, lString16 id, lString16 filename ) : _type(type), _title(title), _id( id ), _filename( filename ) { } - HyphDictType getType() { return _type; } - lString16 getTitle() { return _title; } - lString16 getId() { return _id; } - lString16 getFilename() { return _filename; } + HyphDictType getType() const { return _type; } + lString16 getTitle() const { return _title; } + lString16 getId() const { return _id; } + lString16 getFilename() const { return _filename; } bool activate(); - virtual lUInt32 getHash() { return getTitle().getHash(); } + virtual lUInt32 getHash() const { return getTitle().getHash(); } virtual ~HyphDictionary() { } }; @@ -98,7 +98,7 @@ class HyphDictionaryList HyphDictionary * get( int index ) { return (index>=0 && index<+_list.length()) ? _list[index] : NULL; } HyphDictionaryList() { addDefault(); } bool open(lString16 hyphDirectory, bool clear = true); - HyphDictionary * find( lString16 id ); + HyphDictionary * find( const lString16& id ); bool activate( lString16 id ); }; @@ -109,12 +109,18 @@ class HyphDictionaryList // the document if the book does not contain any language tag, and // we end up going with it anyway. -class HyphDictionary; -class HyphDictionaryList; class TexHyph; class AlgoHyph; class SoftHyphensHyph; +class HyphDataLoader +{ +public: + HyphDataLoader() {} + virtual ~HyphDataLoader() {} + virtual LVStreamRef loadData(lString16 id) = 0; +}; + /// hyphenation manager class HyphMan { @@ -127,6 +133,7 @@ class HyphMan // static HyphDictionary * _selectedDictionary; static HyphDictionaryList * _dictList; // available hyph dict files (+ none/algo/softhyphens) static LVHashTable _loaded_hyph_methods; // methods with loaded dictionaries + static HyphDataLoader* _dataLoader; static int _LeftHyphenMin; static int _RightHyphenMin; static int _TrustSoftHyphens; @@ -134,8 +141,9 @@ class HyphMan static void uninit(); static bool initDictionaries(lString16 dir, bool clear = true); static HyphDictionaryList * getDictList() { return _dictList; } + static bool addDictionaryItem(HyphDictionary* dict); + static void setDataLoader(HyphDataLoader* loader); static bool activateDictionary( lString16 id ) { return _dictList->activate(id); } - static bool activateDictionaryFromStream( LVStreamRef stream ); // used by CoolReader on Android static HyphDictionary * getSelectedDictionary(); // was: { return _selectedDictionary; } static int getLeftHyphenMin() { return _LeftHyphenMin; } static int getRightHyphenMin() { return _RightHyphenMin; } diff --git a/crengine/include/lvstyles.h b/crengine/include/lvstyles.h index 8b1a155b2..ae8798cbc 100644 --- a/crengine/include/lvstyles.h +++ b/crengine/include/lvstyles.h @@ -72,18 +72,19 @@ enum css_style_rec_important_bit { imp_bit_border_color_left = 1ULL << 45, imp_bit_background_image = 1ULL << 46, imp_bit_background_repeat = 1ULL << 47, - imp_bit_background_attachment = 1ULL << 48, - imp_bit_background_position = 1ULL << 49, - imp_bit_border_collapse = 1ULL << 50, - imp_bit_border_spacing_h = 1ULL << 51, - imp_bit_border_spacing_v = 1ULL << 52, - imp_bit_orphans = 1ULL << 53, - imp_bit_widows = 1ULL << 54, - imp_bit_float = 1ULL << 55, - imp_bit_clear = 1ULL << 56, - imp_bit_direction = 1ULL << 57, - imp_bit_content = 1ULL << 58, - imp_bit_cr_hint = 1ULL << 59 + imp_bit_background_position = 1ULL << 48, + imp_bit_background_size_h = 1ULL << 49, + imp_bit_background_size_v = 1ULL << 50, + imp_bit_border_collapse = 1ULL << 51, + imp_bit_border_spacing_h = 1ULL << 52, + imp_bit_border_spacing_v = 1ULL << 53, + imp_bit_orphans = 1ULL << 54, + imp_bit_widows = 1ULL << 55, + imp_bit_float = 1ULL << 56, + imp_bit_clear = 1ULL << 57, + imp_bit_direction = 1ULL << 58, + imp_bit_content = 1ULL << 59, + imp_bit_cr_hint = 1ULL << 60 }; // Style handling flags @@ -101,8 +102,8 @@ struct css_style_rec_tag { int refCount; // for reference counting lUInt32 hash; // cache calculated hash value here lUInt64 important; // bitmap for !important (used only by LVCssDeclaration) - // we have currently below 60 css properties - // lvstsheet knows about 82, which are mapped to these 60 + // we have currently below 61 css properties + // lvstsheet knows about 83, which are mapped to these 61 // update bits above if you add new properties below lUInt64 importance; // bitmap for important bit's importance/origin // (allows for 2 level of !important importance) @@ -142,8 +143,8 @@ struct css_style_rec_tag { css_length_t border_color[4]; ///< border-top-color, -right-, -bottom-, -left- lString8 background_image; css_background_repeat_value_t background_repeat; - css_background_attachment_value_t background_attachment; css_background_position_value_t background_position; + css_length_t background_size[2];//first width and second height css_border_collapse_value_t border_collapse; css_length_t border_spacing[2];//first horizontal and the second vertical spacing css_orphans_widows_value_t orphans; @@ -194,7 +195,6 @@ struct css_style_rec_tag { , border_style_right(css_border_none) , border_style_left(css_border_none) , background_repeat(css_background_r_none) - , background_attachment(css_background_a_none) , background_position(css_background_p_none) , border_collapse(css_border_seperate) , orphans(css_orphans_widows_inherit) @@ -215,6 +215,8 @@ struct css_style_rec_tag { border_width[1] = css_length_t(css_val_unspecified, 0); border_width[2] = css_length_t(css_val_unspecified, 0); border_width[3] = css_length_t(css_val_unspecified, 0); + background_size[0] = css_length_t(css_val_unspecified, 0); + background_size[1] = css_length_t(css_val_unspecified, 0); } void AddRef() { refCount++; } int Release() { return --refCount; } @@ -278,7 +280,6 @@ enum lvdom_element_render_method erm_block, ///< render as block element (render as containing other elements) erm_final, ///< final element: render the whole it's content as single render block erm_inline, ///< inline element - erm_runin, ///< run-in (used as a solution to inline FB2 footnotes) erm_table, ///< table element: render as table erm_table_row_group, ///< table row group erm_table_header_group, ///< table header group diff --git a/crengine/include/lvtextfm.h b/crengine/include/lvtextfm.h index b8a528ea4..ea82cb1e9 100644 --- a/crengine/include/lvtextfm.h +++ b/crengine/include/lvtextfm.h @@ -62,7 +62,7 @@ extern "C" { // (Don't waste the 4th bit not used in the 4-bits sets above) #define LTEXT_FLAG_OWNTEXT 0x0008 // store local copy of text instead of pointer #define LTEXT_IS_LINK 0x0080 // source text is a link (to gather in-page footnotes) -#define LTEXT_RUNIN_FLAG 0x8000 // element display mode is runin (used with FB2 footnotes) +#define LTEXT__AVAILABLE_BIT_16__ 0x8000 // Text white-space and hyphenation handling #define LTEXT_FLAG_PREFORMATTED 0x00010000 // text is preformatted (white-space: pre, pre-wrap, break-spaces) diff --git a/crengine/src/hyphman.cpp b/crengine/src/hyphman.cpp index e456c81b0..8c9e089f8 100644 --- a/crengine/src/hyphman.cpp +++ b/crengine/src/hyphman.cpp @@ -55,6 +55,8 @@ int HyphMan::_LeftHyphenMin = HYPH_DEFAULT_HYPHEN_MIN; int HyphMan::_RightHyphenMin = HYPH_DEFAULT_HYPHEN_MIN; int HyphMan::_TrustSoftHyphens = HYPH_DEFAULT_TRUST_SOFT_HYPHENS; LVHashTable HyphMan::_loaded_hyph_methods(16); +HyphDataLoader* HyphMan::_dataLoader = NULL; + // Obsolete: now fetched from TextLangMan main lang TextLangCfg // HyphDictionary * HyphMan::_selectedDictionary = NULL; @@ -140,6 +142,28 @@ typedef struct { } hyph_index_item_t; #pragma pack(pop) +class HyphDataLoaderFromFile: public HyphDataLoader +{ +public: + HyphDataLoaderFromFile() : HyphDataLoader() {} + virtual ~HyphDataLoaderFromFile() {} + virtual LVStreamRef loadData(lString16 id) { + HyphDictionaryList* dictList = HyphMan::getDictList(); + HyphDictionary * p = dictList->find(id); + if ( !p ) + return LVStreamRef(); + if ( p->getType() == HDT_NONE || + p->getType() == HDT_ALGORITHM || + p->getType() == HDT_SOFTHYPHENS || + ( p->getType() != HDT_DICT_ALAN && p->getType() != HDT_DICT_TEX) ) + return LVStreamRef(); + lString16 filename = p->getFilename(); + return LVOpenFileStream( filename.c_str(), LVOM_READ ); + } +}; + + + void HyphMan::uninit() { // Avoid existing frontend code to have to call it: @@ -154,6 +178,9 @@ void HyphMan::uninit() if ( _dictList ) delete _dictList; _dictList = NULL; + if ( _dataLoader ) + delete _dataLoader; + _dataLoader = NULL; /* Obsolete: _selectedDictionary = NULL; if ( HyphMan::_method != &ALGO_HYPH && HyphMan::_method != &NO_HYPH && HyphMan::_method != &SOFTHYPHENS_HYPH ) @@ -162,60 +189,14 @@ void HyphMan::uninit() */ } -bool HyphMan::activateDictionaryFromStream( LVStreamRef stream ) -{ - if ( stream.isNull() ) - return false; - /* Obsolete: - CRLog::trace("remove old hyphenation method"); - if ( HyphMan::_method != &NO_HYPH && HyphMan::_method != &ALGO_HYPH && HyphMan::_method != &SOFTHYPHENS_HYPH && HyphMan::_method ) { - delete HyphMan::_method; - HyphMan::_method = &NO_HYPH; - } - */ - CRLog::trace("creating new TexHyph method"); - TexHyph * method = new TexHyph(HYPH_DICT_ID_DICTIONARY); - CRLog::trace("loading from file"); - if ( !method->load( stream ) ) { - CRLog::error("HyphMan::activateDictionaryFromStream: Cannot open hyphenation dictionary from stream" ); - delete method; - return false; - } - if (method->largest_overflowed_word) - printf("CRE WARNING: hyph dict from stream: some hyphenation patterns were too long and have been ignored: increase MAX_PATTERN_SIZE from %d to %d\n", MAX_PATTERN_SIZE, method->largest_overflowed_word); - CRLog::debug("Dictionary is loaded successfully. Activating."); - - // Replace any previously dict loaded from stream - HyphMethod * prev_method; - if ( _loaded_hyph_methods.get(HYPH_DICT_ID_DICTIONARY, prev_method) ) { - delete prev_method; - _loaded_hyph_methods.remove(HYPH_DICT_ID_DICTIONARY); - } - _loaded_hyph_methods.set(HYPH_DICT_ID_DICTIONARY, method); - - if (!_dictList) - _dictList = new HyphDictionaryList(); - /* Obsolete: - HyphMan::_method = method; - */ - if ( HyphMan::_dictList->find(lString16(HYPH_DICT_ID_DICTIONARY))==NULL ) { - HyphDictionary * dict = new HyphDictionary( HDT_DICT_ALAN, cs16("Dictionary"), lString16(HYPH_DICT_ID_DICTIONARY), lString16::empty_str ); - HyphMan::_dictList->add(dict); - /* Obsolete: - HyphMan::_selectedDictionary = dict; - */ - } - TextLangMan::setMainLangFromHyphDict( HYPH_DICT_ID_DICTIONARY ); - CRLog::trace("Activation is done"); - return true; -} - bool HyphMan::initDictionaries(lString16 dir, bool clear) { if (clear && _dictList) delete _dictList; if (clear || !_dictList) _dictList = new HyphDictionaryList(); + if (NULL == _dataLoader) + _dataLoader = new HyphDataLoaderFromFile; if (_dictList->open(dir, clear)) { if ( !_dictList->activate( lString16(DEF_HYPHENATION_DICT) ) ) _dictList->activate( lString16(HYPH_DICT_ID_ALGORITHM) ); @@ -226,6 +207,21 @@ bool HyphMan::initDictionaries(lString16 dir, bool clear) } } +// for android +bool HyphMan::addDictionaryItem(HyphDictionary* dict) +{ + if (_dictList->find(dict->getId())) + return false; + _dictList->add(dict); + return true; +} + +void HyphMan::setDataLoader(HyphDataLoader* loader) { + if (_dataLoader) + delete _dataLoader; + _dataLoader = loader; +} + bool HyphMan::setLeftHyphenMin( int left_hyphen_min ) { if (left_hyphen_min >= HYPH_MIN_HYPHEN_MIN && left_hyphen_min <= HYPH_MAX_HYPHEN_MIN) { HyphMan::_LeftHyphenMin = left_hyphen_min; @@ -269,7 +265,7 @@ HyphDictionary * HyphMan::getSelectedDictionary() { } HyphMethod * HyphMan::getHyphMethodForDictionary( lString16 id, int leftHyphenMin, int rightHyphenMin ) { - if ( id.empty() ) + if ( id.empty() || NULL == _dataLoader) return &NO_HYPH; HyphDictionary * p = _dictList->find(id); if ( !p || p->getType() == HDT_NONE ) @@ -285,21 +281,20 @@ HyphMethod * HyphMan::getHyphMethodForDictionary( lString16 id, int leftHyphenMi // printf("getHyphMethodForDictionary reusing cached %s\n", UnicodeToUtf8(p->getFilename()).c_str()); return method; } - lString16 filename = p->getFilename(); - LVStreamRef stream = LVOpenFileStream( filename.c_str(), LVOM_READ ); + LVStreamRef stream = _dataLoader->loadData(id); if ( stream.isNull() ) { - CRLog::error("Cannot open hyphenation dictionary %s", UnicodeToUtf8(filename).c_str() ); + CRLog::error("Cannot open hyphenation dictionary %s", UnicodeToUtf8(id).c_str() ); return &NO_HYPH; } TexHyph * newmethod = new TexHyph(id, leftHyphenMin, rightHyphenMin); if ( !newmethod->load( stream ) ) { - CRLog::error("Cannot open hyphenation dictionary %s", UnicodeToUtf8(filename).c_str() ); + CRLog::error("Cannot open hyphenation dictionary %s", UnicodeToUtf8(id).c_str() ); delete newmethod; return &NO_HYPH; } // printf("CRE: loaded hyphenation dict %s\n", UnicodeToUtf8(id).c_str()); if ( newmethod->largest_overflowed_word ) - printf("CRE WARNING: %s: some hyphenation patterns were too long and have been ignored: increase MAX_PATTERN_SIZE from %d to %d\n", UnicodeToUtf8(filename).c_str(), MAX_PATTERN_SIZE, newmethod->largest_overflowed_word); + printf("CRE WARNING: %s: some hyphenation patterns were too long and have been ignored: increase MAX_PATTERN_SIZE from %d to %d\n", UnicodeToUtf8(id).c_str(), MAX_PATTERN_SIZE, newmethod->largest_overflowed_word); _loaded_hyph_methods.set(id, newmethod); return newmethod; } @@ -382,7 +377,7 @@ void HyphDictionaryList::addDefault() } -HyphDictionary * HyphDictionaryList::find( lString16 id ) +HyphDictionary * HyphDictionaryList::find( const lString16& id ) { for ( int i=0; i<_list.length(); i++ ) { if ( _list[i]->getId() == id ) diff --git a/crengine/src/lvdocview.cpp b/crengine/src/lvdocview.cpp index 885eb9b5c..3f3701bf0 100644 --- a/crengine/src/lvdocview.cpp +++ b/crengine/src/lvdocview.cpp @@ -6100,7 +6100,6 @@ void LVDocView::propsUpdateDefaults(CRPropRef props) { props->setIntDef(PROP_STATUS_FONT_SIZE, fs); lString16 hyph = props->getStringDef(PROP_HYPHENATION_DICT, DEF_HYPHENATION_DICT); -#if !defined(ANDROID) HyphDictionaryList * dictlist = HyphMan::getDictList(); if (dictlist) { if (dictlist->find(hyph)) @@ -6109,7 +6108,6 @@ void LVDocView::propsUpdateDefaults(CRPropRef props) { props->setStringDef(PROP_HYPHENATION_DICT, lString16( HYPH_DICT_ID_ALGORITHM)); } -#endif props->setIntDef(PROP_STATUS_LINE, 0); props->setIntDef(PROP_SHOW_TITLE, 1); props->setIntDef(PROP_SHOW_TIME, 1); @@ -6373,7 +6371,6 @@ CRPropRef LVDocView::propsApply(CRPropRef props) { fontSize = MAX_STATUS_FONT_SIZE; setStatusFontSize(fontSize);//cr_font_sizes value = lString16::itoa(fontSize); -#if !defined(ANDROID) } else if (name == PROP_HYPHENATION_DICT) { // hyphenation dictionary lString16 id = props->getStringDef(PROP_HYPHENATION_DICT, @@ -6408,7 +6405,6 @@ CRPropRef LVDocView::propsApply(CRPropRef props) { HyphMan::setTrustSoftHyphens(trustSoftHyphens); REQUEST_RENDER("propsApply hyphenation trust_soft_hyphens") } -#endif } else if (name == PROP_TEXTLANG_MAIN_LANG) { lString16 lang = props->getStringDef(PROP_TEXTLANG_MAIN_LANG, TEXTLANG_DEFAULT_MAIN_LANG); if ( lang != TextLangMan::getMainLang() ) { diff --git a/crengine/src/lvrend.cpp b/crengine/src/lvrend.cpp index 52b0249a9..e12a05b48 100644 --- a/crengine/src/lvrend.cpp +++ b/crengine/src/lvrend.cpp @@ -580,7 +580,6 @@ class CCRTable { } break; case erm_inline: - case erm_runin: // do nothing break; } @@ -2141,9 +2140,8 @@ lUInt32 styleToTextFmtFlags( bool is_block, const css_style_ref_t & style, lUInt if ( is_block ) { // text alignment flags flg = oldflags & ~LTEXT_FLAG_NEWLINE; - if ( !(oldflags & LTEXT_RUNIN_FLAG) ) { - switch (style->text_align) - { + switch (style->text_align) + { case css_ta_left: flg |= LTEXT_ALIGN_LEFT; break; @@ -2165,9 +2163,9 @@ lUInt32 styleToTextFmtFlags( bool is_block, const css_style_ref_t & style, lUInt case css_ta_auto: // shouldn't happen (only accepted with text-align-last) case css_ta_inherit: break; - } - switch (style->text_align_last) - { + } + switch (style->text_align_last) + { case css_ta_left: flg |= LTEXT_LAST_LINE_ALIGN_LEFT; break; @@ -2189,12 +2187,8 @@ lUInt32 styleToTextFmtFlags( bool is_block, const css_style_ref_t & style, lUInt case css_ta_auto: // let flg have none of the above set, which will mean "auto" case css_ta_inherit: break; - } } } - else if ( style->display == css_d_run_in ) { - flg |= LTEXT_RUNIN_FLAG; - } // We should clean these flags that we got from the parent node via baseFlags: // CSS white-space inheritance is correctly handled via styles (so, no need // for this alternative way to ensure inheritance with flags), but might have @@ -2462,6 +2456,7 @@ void renderFinalBlock( ldomNode * enode, LFormattedText * txform, RenderRectAcce return; } + css_style_ref_t style = enode->getStyle(); bool is_object = false; const css_elem_def_props_t * ntype = enode->getElementTypePtr(); if ( ntype && ntype->is_object ) @@ -2479,7 +2474,7 @@ void renderFinalBlock( ldomNode * enode, LFormattedText * txform, RenderRectAcce // when recursing its children which are inline), it will also set // horitontal alignment flags. bool is_block = rm == erm_final; - lUInt32 flags = styleToTextFmtFlags( is_block, enode->getStyle(), baseflags, direction ); + lUInt32 flags = styleToTextFmtFlags( is_block, style, baseflags, direction ); // Note: // - baseflags (passed by reference) is shared and re-used by this node's siblings // (all inline); it should carry newline/horizontal aligment flag, which should @@ -2490,11 +2485,41 @@ void renderFinalBlock( ldomNode * enode, LFormattedText * txform, RenderRectAcce int width = fmt->getWidth(); int em = enode->getFont()->getSize(); - css_style_ref_t style = enode->getStyle(); ldomNode * parent = enode->getParentNode(); // Needed for various checks below if (parent && parent->isNull()) parent = NULL; + // Nodes with "display: run-in" are inline nodes brought at start of the final node + bool isRunIn = style->display == css_d_run_in; + if ( isRunIn ) { + // The text alignment of the paragraph should come from the following + // sibling node. The one set from the parent final node has probably + // not yet been consumed, so update it. + if ( baseflags & LTEXT_FLAG_NEWLINE ) { + if ( enode->getNodeIndex() == 0 && parent && parent->getChildCount() > 1 ) { + ldomNode * next_sibling = parent->getChildNode(1); + if ( next_sibling && !next_sibling->isNull() ) { + // next_sibling is an original block node that should have + // been erm_final, but has been made erm_inline so it can + // be prepended with the run-in node content. + lUInt32 next_sibling_flags = styleToTextFmtFlags( true, next_sibling->getStyle(), baseflags, direction ); + // Grab only the alignment flags + lUInt32 align_flags_mask = LTEXT_FLAG_NEWLINE | (LTEXT_FLAG_NEWLINE<display==css_d_run_in; - if ( thisIsRunIn ) - flags |= LTEXT_RUNIN_FLAG; // Some elements add some generated content lUInt16 nodeElementId = enode->getNodeId(); @@ -3150,10 +3172,7 @@ void renderFinalBlock( ldomNode * enode, LFormattedText * txform, RenderRectAcce } } - // Note: CSS "display: run-in" is no longer used with our epub.css (it is - // used with older css files for "body[name="notes"] section title", either - // for crengine internal footnotes displaying, or some FB2 features) - if ( thisIsRunIn ) { + if ( isRunIn ) { // append space to run-in object LVFontRef font = enode->getFont(); css_style_ref_t style = enode->getStyle(); @@ -3161,9 +3180,7 @@ void renderFinalBlock( ldomNode * enode, LFormattedText * txform, RenderRectAcce lUInt32 bgcl = style->background_color.type!=css_val_color ? 0xFFFFFFFF : style->background_color.value; lChar16 delimiter[] = {UNICODE_NO_BREAK_SPACE, UNICODE_NO_BREAK_SPACE}; //160 txform->AddSourceLine( delimiter, sizeof(delimiter)/sizeof(lChar16), cl, bgcl, font.get(), lang_cfg, - LTEXT_RUNIN_FLAG | LTEXT_FLAG_PREFORMATTED | LTEXT_FLAG_OWNTEXT, - line_h, valign_dy, 0, NULL ); - flags &= ~LTEXT_RUNIN_FLAG; + LTEXT_FLAG_PREFORMATTED | LTEXT_FLAG_OWNTEXT, line_h, valign_dy, 0, NULL ); } } @@ -3250,7 +3267,6 @@ void renderFinalBlock( ldomNode * enode, LFormattedText * txform, RenderRectAcce break; } } - //baseflags &= ~LTEXT_RUNIN_FLAG; if ( rm == erm_final && (baseflags & LTEXT_SRC_IS_CLEAR_BOTH) ) { // We're leaving the top final node with a clear: not consumed // (set by a last or single
), with no follow-up @@ -3464,8 +3480,9 @@ void copystyle( css_style_ref_t source, css_style_ref_t dest ) dest->border_color[3]=source->border_color[3]; dest->background_image=source->background_image; dest->background_repeat=source->background_repeat; - dest->background_attachment=source->background_attachment; dest->background_position=source->background_position; + dest->background_size[0]=source->background_size[0]; + dest->background_size[1]=source->background_size[1]; dest->border_collapse=source->border_collapse; dest->border_spacing[0]=source->border_spacing[0]; dest->border_spacing[1]=source->border_spacing[1]; @@ -7824,8 +7841,79 @@ void DrawBackgroundImage(ldomNode *enode,LVDrawBuf & drawbuf,int x0,int y0,int d lString16 filepath = lString16(style->background_image.c_str()); LVImageSourceRef img = enode->getParentNode()->getDocument()->getObjectImageSource(filepath); if (!img.isNull()) { + // Native image size int img_w =img->GetWidth(); int img_h =img->GetHeight(); + + // See if background-size specified and we need to adjust image native size + css_length_t bg_w = style->background_size[0]; + css_length_t bg_h = style->background_size[1]; + if ( bg_w.type != css_val_unspecified || bg_w.value != 0 || bg_h.type != css_val_unspecified || bg_h.value != 0 ) { + int new_w = 0; + int new_h = 0; + RenderRectAccessor fmt( enode ); + int container_w = fmt.getWidth(); + int container_h = fmt.getHeight(); + bool check_lengths = true; + if ( bg_w.type == css_val_unspecified && bg_h.type == css_val_unspecified ) { + if ( bg_w.value == css_generic_contain && bg_h.value == css_generic_contain ) { + // Image should be fully contained in container (no crop) + int scale_w = 1024 * container_w / img_w; + int scale_h = 1024 * container_h / img_h; + if ( scale_w < scale_h ) { + new_w = container_w; + new_h = img_h * scale_w / 1024; + } + else { + new_h = container_h; + new_w = img_w * scale_h / 1024; + } + check_lengths = false; + } + else if ( bg_w.value == css_generic_cover && bg_h.value == css_generic_cover ) { + // Image should fully cover container (crop allowed) + int scale_w = 1024 * container_w / img_w; + int scale_h = 1024 * container_h / img_h; + if ( scale_w > scale_h ) { + new_w = container_w; + new_h = img_h * scale_w / 1024; + } + else { + new_h = container_h; + new_w = img_w * scale_h / 1024; + } + check_lengths = false; + } + } + if ( check_lengths ) { + int em = enode->getFont()->getSize(); + // These will compute to 0 if (css_val_unspecified, 0) when really not specified + new_w = lengthToPx(style->background_size[0], container_w, em); + new_h = lengthToPx(style->background_size[1], container_h, em); + if ( new_w == 0 ) { + if ( new_h == 0 ) { // keep image native size + new_h = img_h; + new_w = img_w; + } + else { // use style height, keep aspect ratio + new_w = img_w * new_h / img_h; + } + } + else if ( new_h == 0 ) { // use style width, keep aspect ratio + new_h = new_w * img_h / img_w; + } + } + if ( new_w == 0 || new_h == 0 ) { + // width or height computed to 0: nothing to draw + return; + } + if ( new_w != img_w || new_h != img_h ) { + img = LVCreateStretchFilledTransform(img, new_w, new_h, IMG_TRANSFORM_STRETCH, IMG_TRANSFORM_STRETCH, 0, 0); + img_w = new_w; + img_h = new_h; + } + } + // We can use some crengine facilities for background repetition and position, // which has the advantage that img will be decoded once even if tiling it many // times and if the target is many screen-heights long (like could be). @@ -7921,13 +8009,21 @@ void DrawBackgroundImage(ldomNode *enode,LVDrawBuf & drawbuf,int x0,int y0,int d draw_y = 0; } // Ready to have crengine do all the work. - // (Inspired from LVDocView::drawPageBackground(), we have to do it that complex - // way to avoid memory leaks; and we have to use a 16bpp LVColorDrawBuf, - // 32bpp would mess colors up). - LVRef buf = LVRef( new LVColorDrawBuf(img_w, img_h, 16) ); - buf->Draw(img, 0, 0, img_w, img_h, false); // (dither=false doesn't matter with a color buffer) - LVImageSourceRef src = LVCreateDrawBufImageSource(buf.get(), false); - LVImageSourceRef transformed = LVCreateStretchFilledTransform(src, transform_w, transform_h, + /* Looks like we don't need that: + + // (Inspired from LVDocView::drawPageBackground(), we have to do it that complex + // way to avoid memory leaks; and we have to use a 16bpp LVColorDrawBuf, + // 32bpp would mess colors up). + LVRef buf = LVRef( new LVColorDrawBuf(img_w, img_h, 16) ); + buf->Draw(img, 0, 0, img_w, img_h, false); // (dither=false doesn't matter with a color buffer) + LVImageSourceRef src = LVCreateDrawBufImageSource(buf.get(), false); + LVImageSourceRef transformed = LVCreateStretchFilledTransform(src, transform_w, transform_h, + + We can just transform the original image, which will work in its original + colorspace/depth, ensure alpha/transparency, and will be converted only + at the end to the final drawbuf bit depth. + */ + LVImageSourceRef transformed = LVCreateStretchFilledTransform(img, transform_w, transform_h, hori_transform, vert_transform, transform_x, transform_y); // We use the DrawBuf clip facility to ensure we don't draw outside this node fmt lvRect orig_clip; diff --git a/crengine/src/lvstsheet.cpp b/crengine/src/lvstsheet.cpp index eb2692185..32f48ed87 100644 --- a/crengine/src/lvstsheet.cpp +++ b/crengine/src/lvstsheet.cpp @@ -104,8 +104,8 @@ enum css_decl_code { cssd_background, cssd_background_image, cssd_background_repeat, - cssd_background_attachment, cssd_background_position, + cssd_background_size, cssd_border_collapse, cssd_border_spacing, cssd_orphans, @@ -197,8 +197,8 @@ static const char * css_decl_name[] = { "background", "background-image", "background-repeat", - "background-attachment", "background-position", + "background-size", "border-collapse", "border-spacing", "orphans", @@ -393,6 +393,7 @@ static bool parse_number_value( const char * & str, css_length_t & value, bool accept_negative=false, bool accept_auto=false, bool accept_normal=false, + bool accept_contain_cover=false, bool is_font_size=false ) { const char * orig_pos = str; @@ -414,6 +415,18 @@ static bool parse_number_value( const char * & str, css_length_t & value, value.value = css_generic_normal; return true; } + if ( accept_contain_cover ) { + if ( substr_icompare( "contain", str ) ) { + value.type = css_val_unspecified; + value.value = css_generic_contain; + return true; + } + if ( substr_icompare( "cover", str ) ) { + value.type = css_val_unspecified; + value.value = css_generic_cover; + return true; + } + } if ( is_font_size ) { // Absolute-size keywords, based on the default font size (which is medium) // Factors as suggested in https://drafts.csswg.org/css-fonts-3/#absolute-size-value @@ -1371,10 +1384,15 @@ static void resolve_url_path( lString8 & str, lString16 codeBase ) { if (path.startsWith(L"\"") || path.startsWith(L"'")) path = path.substr(1); if (path.endsWith(L"\"") || path.endsWith(L"'")) path = path.substr(0, path.length() - 1); path.trim(); - // We assume it's a path to a local file in the container, so we don't try - // to check if it's a remote url (as we can't fetch its content anyway). - if ( !codeBase.empty() ) { - path = LVCombinePaths( codeBase, path ); + if (path.startsWith(lString16("data:image"))) { + // base64 encoded image: leave as-is + } + else { + // We assume it's a path to a local file in the container, so we don't try + // to check if it's a remote url (as we can't fetch its content anyway). + if ( !codeBase.empty() ) { + path = LVCombinePaths( codeBase, path ); + } } // printf("url: [%s]+%s => %s\n", UnicodeToLocal(codeBase).c_str(), str.c_str(), UnicodeToUtf8(path).c_str()); str = UnicodeToUtf8(path); @@ -2253,7 +2271,7 @@ bool LVCssDeclaration::parse( const char * &decl, bool higher_importance, lxmlDo if ( prop_code==cssd_font_size ) is_font_size = true; css_length_t len; - if ( parse_number_value( decl, len, accept_percent, accept_negative, accept_auto, accept_normal, is_font_size) ) { + if ( parse_number_value( decl, len, accept_percent, accept_negative, accept_auto, accept_normal, false, is_font_size) ) { buf<<(lUInt32) (prop_code | importance | parse_important(decl)); buf<<(lUInt32) len.type; buf<<(lUInt32) len.value; @@ -2569,7 +2587,17 @@ bool LVCssDeclaration::parse( const char * &decl, bool higher_importance, lxmlDo const char *tmp = decl; int len=0; while (*tmp && *tmp!=';' && *tmp!='}' && *tmp!='!') { - tmp++; len++; + if ( *tmp == '(' && *(tmp-3) == 'u' && *(tmp-2) == 'r' && *(tmp-1) == 'l') { + // Accepts everything until ')' after 'url(', including ';' + // needed when parsing: url("data:image/png;base64,abcd...") + tmp++; len++; + while ( *tmp && *tmp!=')' ) { + tmp++; len++; + } + } + else { + tmp++; len++; + } } str.append(decl,len); decl += len; @@ -2598,9 +2626,6 @@ bool LVCssDeclaration::parse( const char * &decl, bool higher_importance, lxmlDo else if ( n==24 ) n=0; // "inherit" = "left top" } break; - case cssd_background_attachment: - n = parse_name( decl, css_bg_attachment_names, -1 ); - break; case cssd_background: { // Limited parsing of this possibly complex property @@ -2616,14 +2641,24 @@ bool LVCssDeclaration::parse( const char * &decl, bool higher_importance, lxmlDo const char *tmp = decl; int len = 0; while (*tmp && *tmp!=';' && *tmp!='}' && *tmp!='!') { - tmp++; len++; + if ( *tmp == '(' && *(tmp-3) == 'u' && *(tmp-2) == 'r' && *(tmp-1) == 'l') { + // Accepts everything until ')' after 'url(', including ';' + // needed when parsing: url("data:image/png;base64,abcd...") + tmp++; len++; + while ( *tmp && *tmp!=')' ) { + tmp++; len++; + } + } + else { + tmp++; len++; + } } lString8 str; str.append(decl,len); - if ( Utf8ToUnicode(str).lowercase().startsWith("url") ) { + if ( Utf8ToUnicode(str).lowercase().startsWith("url(") ) { tmp = str.c_str(); len = 0; - while (*tmp && *tmp!=';' && *tmp!='}' && *tmp!=')') { + while (*tmp && *tmp!=')') { tmp++; len++; } len = len + 1; @@ -2681,6 +2716,34 @@ bool LVCssDeclaration::parse( const char * &decl, bool higher_importance, lxmlDo } } break; + case cssd_background_size: + { + // https://developer.mozilla.org/en-US/docs/Web/CSS/background-size + css_length_t len[2]; + int i; + for (i = 0; i < 2; i++) { + if ( !parse_number_value( decl, len[i], true, false, true, false, true ) ) + break; + } + if (i) { + if (i == 1) { // Only 1 value parsed + if ( len[0].type == css_val_unspecified ) { // "auto", "contain" or "cover" + len[1].type = css_val_unspecified; + len[1].value = len[0].value; + } + else { // first value is a length: second value should be "auto" + len[1].type = css_val_unspecified; + len[1].value = css_generic_auto; + } + } + buf<<(lUInt32) (prop_code | importance | parse_important(decl)); + for (i = 0; i < 2; i++) { + buf<<(lUInt32) len[i].type; + buf<<(lUInt32) len[i].value; + } + } + } + break; case cssd_border_spacing: { css_length_t len[2]; @@ -2992,12 +3055,13 @@ void LVCssDeclaration::apply( css_style_rec_t * style ) case cssd_background_repeat: style->Apply( (css_background_repeat_value_t) *p++, &style->background_repeat, imp_bit_background_repeat, is_important ); break; - case cssd_background_attachment: - style->Apply( (css_background_attachment_value_t) *p++, &style->background_attachment, imp_bit_background_attachment, is_important ); - break; case cssd_background_position: style->Apply( (css_background_position_value_t) *p++, &style->background_position, imp_bit_background_position, is_important ); break; + case cssd_background_size: + style->Apply( read_length(p), &style->background_size[0], imp_bit_background_size_h, is_important ); + style->Apply( read_length(p), &style->background_size[1], imp_bit_background_size_v, is_important ); + break; case cssd_border_spacing: style->Apply( read_length(p), &style->border_spacing[0], imp_bit_border_spacing_h, is_important ); style->Apply( read_length(p), &style->border_spacing[1], imp_bit_border_spacing_v, is_important ); diff --git a/crengine/src/lvstyles.cpp b/crengine/src/lvstyles.cpp index a070e652b..a16ec0f6f 100644 --- a/crengine/src/lvstyles.cpp +++ b/crengine/src/lvstyles.cpp @@ -44,7 +44,7 @@ lUInt32 calcHash(font_ref_t & f) lUInt32 calcHash(css_style_rec_t & rec) { if ( !rec.hash ) - rec.hash = ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( + rec.hash = (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( (lUInt32)(rec.important >> 32)) * 31 + (lUInt32)(rec.important & 0xFFFFFFFFULL)) * 31 + (lUInt32)(rec.importance >> 32)) * 31 @@ -93,8 +93,9 @@ lUInt32 calcHash(css_style_rec_t & rec) + (lUInt32)rec.border_color[2].pack()) * 31 + (lUInt32)rec.border_color[3].pack()) * 31 + (lUInt32)rec.background_repeat)*31 - + (lUInt32)rec.background_attachment)*31 + (lUInt32)rec.background_position)*31 + + (lUInt32)rec.background_size[0].pack())*31 + + (lUInt32)rec.background_size[1].pack())*31 + (lUInt32)rec.font_family) * 31 + (lUInt32)rec.border_collapse)*31 + (lUInt32)rec.border_spacing[0].pack())*31 @@ -161,8 +162,9 @@ bool operator == (const css_style_rec_t & r1, const css_style_rec_t & r2) r1.border_color[3]==r2.border_color[3]&& r1.background_image==r2.background_image&& r1.background_repeat==r2.background_repeat&& - r1.background_attachment==r2.background_attachment&& r1.background_position==r2.background_position&& + r1.background_size[0]==r2.background_size[0]&& + r1.background_size[1]==r2.background_size[1]&& r1.border_collapse==r2.border_collapse&& r1.border_spacing[0]==r2.border_spacing[0]&& r1.border_spacing[1]==r2.border_spacing[1]&& @@ -349,8 +351,9 @@ bool css_style_rec_t::serialize( SerialBuf & buf ) ST_PUT_LEN4(border_color); buf<>background_image; ST_GET_ENUM(css_background_repeat_value_t ,background_repeat); - ST_GET_ENUM(css_background_attachment_value_t ,background_attachment); ST_GET_ENUM(css_background_position_value_t ,background_position); + ST_GET_LEN(background_size[0]); + ST_GET_LEN(background_size[1]); ST_GET_ENUM(css_border_collapse_value_t ,border_collapse); ST_GET_LEN(border_spacing[0]); ST_GET_LEN(border_spacing[1]); diff --git a/crengine/src/lvtextfm.cpp b/crengine/src/lvtextfm.cpp index 41ef269cf..aa297a07e 100644 --- a/crengine/src/lvtextfm.cpp +++ b/crengine/src/lvtextfm.cpp @@ -3400,19 +3400,13 @@ class LVFormatter { // measure paragraph text measureText(); - // run-in detection (mostly only used for FB2 footnotes) + // We keep as 'para' the first source text, as it carries + // the text alignment to use with all added lines. src_text_fragment_t * para = &m_pbuffer->srctext[start]; - int i; - for ( i=start; isrctext[i].flags & LTEXT_RUNIN_FLAG) ) { - para = &m_pbuffer->srctext[i]; - break; - } - } // detect case with inline preformatted text inside block with line feeds -- override align=left for this case bool preFormattedOnly = true; - for ( i=start; isrctext[i].flags & LTEXT_FLAG_PREFORMATTED) ) { preFormattedOnly = false; break; @@ -3420,7 +3414,7 @@ class LVFormatter { } if ( preFormattedOnly ) { bool lfFound = false; - for ( i=0; isrctextlen; i++ ) { -// int flg = m_pbuffer->srctext[i].flags; -// if ( (flg & LTEXT_RUNIN_FLAG) ) -// TR("run-in found"); -// TR(" %d: flg=%04x al=%d ri=%d '%s'", i, flg, (flg & LTEXT_FLAG_NEWLINE), (flg & LTEXT_RUNIN_FLAG)?1:0, (flg<EXT_SRC_IS_OBJECT ? "" : LCSTR(lString16(m_pbuffer->srctext[i].t.text, m_pbuffer->srctext[i].t.len)) ) ); -// } -// TR("============================"); int srctextlen = m_pbuffer->srctextlen; int clear_after_last_flag = 0; @@ -4077,14 +4063,13 @@ class LVFormatter { srctextlen -= 1; // Don't process this last srctext } - bool prevRunIn = srctextlen>0 && (m_pbuffer->srctext[0].flags & LTEXT_RUNIN_FLAG); for ( i=1; i<=srctextlen; i++ ) { // Split on LTEXT_FLAG_NEWLINE, mostly set when
met // (we check m_pbuffer->srctext[i], the next srctext that we are not // adding to the current paragraph, as
and its clear= are carried // by the following text.) bool isLastPara = (i == srctextlen); - if ( isLastPara || ((m_pbuffer->srctext[i].flags & LTEXT_FLAG_NEWLINE) && !prevRunIn) ) { + if ( isLastPara || (m_pbuffer->srctext[i].flags & LTEXT_FLAG_NEWLINE) ) { if ( m_pbuffer->srctext[start].flags & LTEXT_SRC_IS_CLEAR_BOTH ) { // (LTEXT_SRC_IS_CLEAR_BOTH is a mask, will match _LEFT and _RIGHT too) floatClearText( m_pbuffer->srctext[start].flags & LTEXT_SRC_IS_CLEAR_BOTH ); @@ -4113,7 +4098,6 @@ class LVFormatter { processParagraph( start, i, isLastPara ); start = i; } - prevRunIn = (isrctext[i].flags & LTEXT_RUNIN_FLAG); } if ( !m_no_clear_own_floats ) { // Clear our own floats so they are fully contained in this final block. diff --git a/crengine/src/lvtinydom.cpp b/crengine/src/lvtinydom.cpp index 404a1d81a..5d4a46605 100644 --- a/crengine/src/lvtinydom.cpp +++ b/crengine/src/lvtinydom.cpp @@ -84,7 +84,7 @@ int gDOMVersionRequested = DOM_VERSION_CURRENT; /// change in case of incompatible changes in swap/cache file format to avoid using incompatible swap file // increment to force complete reload/reparsing of old file -#define CACHE_FILE_FORMAT_VERSION "3.05.42k" +#define CACHE_FILE_FORMAT_VERSION "3.05.43k" /// increment following value to force re-formatting of old book after load #define FORMATTING_VERSION_ID 0x0024 @@ -3975,7 +3975,7 @@ static void writeNodeEx( LVStream * stream, ldomNode * node, lString16Collection rm = erm_final; } } - if ( (rm != erm_inline && rm != erm_runin) || node->isBoxingInlineBox()) { + if ( rm != erm_inline || node->isBoxingInlineBox()) { doNewLineBeforeStartTag = true; doNewLineAfterStartTag = true; // doNewLineBeforeEndTag = false; // done by child elements @@ -4113,7 +4113,6 @@ static void writeNodeEx( LVStream * stream, ldomNode * node, lString16Collection case erm_block: *stream << "B"; break; case erm_final: *stream << "F"; break; case erm_inline: *stream << "i"; break; - case erm_runin: *stream << "r"; break; case erm_table: *stream << "T"; break; case erm_table_row_group: *stream << "TRG"; break; case erm_table_header_group: *stream << "THG"; break; @@ -4969,7 +4968,7 @@ static bool isInlineNode( ldomNode * node ) //int d = node->getStyle()->display; //return ( d==css_d_inline || d==css_d_run_in ); int m = node->getRendMethod(); - return m==erm_inline || m==erm_runin; + return m == erm_inline; } static bool isFloatingNode( ldomNode * node ) @@ -5429,7 +5428,7 @@ static void detectChildTypes( ldomNode * parent, bool & hasBlockItems, bool & ha int m = node->getRendMethod(); if ( d==css_d_none || m==erm_invisible ) continue; - if ( m==erm_inline || m==erm_runin) { //d==css_d_inline || d==css_d_run_in + if ( m==erm_inline ) { //d==css_d_inline || d==css_d_run_in hasInline = true; } else { hasBlockItems = true; @@ -5801,7 +5800,7 @@ bool ldomNode::isEmbeddedBlockBoxingInlineBox(bool inline_box_checks_done) const if ( hasAttribute( attr_T ) ) { // T="EmbeddedBlock" // (no other possible value yet, no need to compare strings) int cm = getChildNode(0)->getRendMethod(); - if ( cm == erm_inline || cm == erm_runin || cm == erm_invisible || cm == erm_killed ) + if ( cm == erm_inline || cm == erm_invisible || cm == erm_killed ) return false; // child has been reset to inline return true; } @@ -5901,7 +5900,7 @@ void ldomNode::initNodeRendMethod() if ( !child->isElement() ) // text node continue; int cm = child->getRendMethod(); - if ( cm == erm_inline || cm == erm_runin ) { + if ( cm == erm_inline ) { has_inline_nodes = true; // We won't be able to make it erm_block continue; } @@ -5945,7 +5944,7 @@ void ldomNode::initNodeRendMethod() if ( !child->isElement() ) // text node continue; int cm = child->getRendMethod(); - if ( cm == erm_inline || cm == erm_runin || cm == erm_invisible || cm == erm_killed ) + if ( cm == erm_inline || cm == erm_invisible || cm == erm_killed ) continue; if ( !isNotBoxWrappingNode( child ) ) continue; @@ -6007,7 +6006,7 @@ void ldomNode::initNodeRendMethod() // runin //CRLog::trace("switch all children elements of <%s> to inline", LCSTR(getNodeName())); recurseElements( resetRendMethodToInline ); - setRendMethod(erm_runin); + setRendMethod(erm_inline); } else if ( d==css_d_list_item_legacy ) { // list item (no more used, obsolete rendering method) setRendMethod(erm_final); @@ -6214,7 +6213,7 @@ void ldomNode::initNodeRendMethod() inBetweenTextNode = prev; prev = getChildNode(i-2); } - if ( prev->isElement() && prev->getRendMethod()==erm_runin ) { + if ( prev->isElement() && prev->getStyle()->display == css_d_run_in ) { bool do_autoboxing = true; int run_in_idx = inBetweenTextNode ? i-2 : i-1; int block_idx = i; @@ -7429,7 +7428,7 @@ void ldomDocumentWriter::OnTagBody() _flags = _currNode->getFlags(); // _flags may have been updated (if white-space: pre) // And only after this we can add the as a first child // element of this BODY node. It will not be displayed thanks to fb2def.h: - // XS_TAG1D( stylesheet, true, css_d_none, css_ws_normal ) + // XS_TAG1D( stylesheet, true, css_d_none, css_ws_inherit ) OnTagOpen(L"", L"stylesheet"); OnTagBody(); OnText(styleText.c_str(), styleText.length(), 0); @@ -11516,7 +11515,6 @@ ldomNode * ldomXPointerEx::getThisBlockNode() return NULL; lvdom_element_render_method rm = node->getRendMethod(); switch ( rm ) { - case erm_runin: // treat as separate block case erm_block: case erm_final: case erm_table: @@ -16126,11 +16124,16 @@ void ldomNode::initNodeStyle() { ldomNode * parent = getParentNode(); + /* This has never triggered over the years, so trust we don't need it. + * This might also improve quite a bit TXT documents handling (where + * the main node may have tens of thousands of
 children, one
+             * for each line of the text file.
+             *
             // DEBUG TEST
             if ( parent->getChildIndex( getDataIndex() )<0 ) {
                 CRLog::error("Invalid parent->child relation for nodes %d->%d", parent->getDataIndex(), getDataIndex() );
             }
-
+            */
 
             //lvdomElementFormatRec * parent_fmt = node->getParentNode()->getRenderData();
             css_style_ref_t style = parent->getStyle();