Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crengine/include/lvxml.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ class LVXMLParser : public LVTextFileBase
LVXMLParserCallback * m_callback;
int m_state;
bool m_in_cdata;
bool m_in_html_style_tag;
bool m_in_html_script_tag;
bool m_trimspaces;
bool SkipSpaces();
Expand Down
3 changes: 3 additions & 0 deletions crengine/src/lvimg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2078,6 +2078,9 @@ static bool lunasvgDrawImageHelper(lunasvg::external_context_t * xcontext, const
if ( doc ) {
ldomNode * node = ((LVNodeImageSource *)xcontext->external_object)->GetSourceNode();
img = doc->getObjectImageSource(Utf8ToUnicode(url), node);
if (img.isNull()) { // url may be url-encoded
img = doc->getObjectImageSource(DecodeHTMLUrlString(Utf8ToUnicode(url)), node);
}
}
else {
// We may be used by frontends without a ldomDocument to render SVG, and
Expand Down
111 changes: 108 additions & 3 deletions crengine/src/lvstsheet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1966,6 +1966,14 @@ class AtRuleLogicalConditionParser {
continue;
}
if ( *str == ')' ) {
if ( level <= 0 ) {
// Closing ')' for a '(' we didn't account for: possibly
// buggy CSS, or we stumbled on some unsupported syntax
// using parens that we didn't parse well
malformed = true;
skip_to_next( str, 0, '{' );
continue;
}
leaveLevel();
str++;
continue;
Expand Down Expand Up @@ -2000,15 +2008,112 @@ class AtRuleLogicalConditionParser {
};

// https://drafts.csswg.org/css-conditional/#at-supports
// https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@supports
class AtSupportsLogicalConditionParser : public AtRuleLogicalConditionParser {
public:
AtSupportsLogicalConditionParser(lxmlDocBase * d)
: AtRuleLogicalConditionParser(d, '{', 0) {}
protected:
virtual void parseCondition(const char * &str) {
// Use our regular declaration parser to see if supported
LVCssDeclaration tmp_decl;
setResult( tmp_decl.parseAndCheckIfSupported( str, doc ) );
skip_spaces( str );
// We may meet either some declaration: "property: value",
// or some function: "selector(a > b)".
// Actually, by specs, a declaration must be enclosed in (...),
// but a function may, as parens can also be used for grouping with
// logical operators. They are handled in AtRuleLogicalConditionParser:parse()
// as such grouping.
// So, we should try here to guess what kind it is.
const char * orig_pos = str;
char ident[16];
if ( !parse_ident(str, ident, 16) ) {
malformed = true;
skip_to_next( str, 0, '{' );
return;
}
skip_spaces( str );
if ( *str != '(' ) { // It's not a function
str = orig_pos;
// Use our regular declaration parser to see if supported
LVCssDeclaration tmp_decl;
setResult( tmp_decl.parseAndCheckIfSupported( str, doc ) );
return;
}
str++; // skip '(' - we'll have to consume the follow up ')' below
skip_spaces( str );
lString8 name(ident);
name.lowercase();
setResult(false);
if ( name == "selector" ) {
// Use our LVCssSelector parser, with for_functional_pseudo_class=true,
// which will have it stop on a ')' (but also on a ',' which is not
// per specs, and should not happen, so this should do)
LVCssSelector tmp_selector;
if ( tmp_selector.parse(str, doc, false, true) ) {
skip_spaces( str ); // should have stopped at a ')'
if ( *str == ')' ) {
str++;
setResult(true);
}
else {
malformed = true;
skip_to_next( str, 0, '{' );
}
}
else {
skip_to_next( str, ')', 0 );
}
}
else if ( name == "font-tech" ) {
// We don't support any (even if we do support some OpenType features
// with Harfbuzz, we don't support (yet) the CSS property 'font-feature',
// which is probably what would be used in a declaration following
// such a "@font-tech(features-opentype) {...}"
skip_to_next( str, ')', 0 );
}
else if ( name == "font-format" ) {
// Not sure we support "collection" (.otc, .ttc) for embedded fonts
if ( substr_icompare( "opentype", str ) ||
substr_icompare( "truetype", str ) ||
substr_icompare( "woff", str ) ||
substr_icompare( "woff2", str ) ) {
skip_spaces( str );
if ( *str == ')' ) {
str++;
setResult(true);
}
else {
skip_to_next( str, ')', 0 );
}
}
else {
malformed = true;
skip_to_next( str, 0, '{' );
}
}
else if ( name == "at-rule" ) {
// We only really support a few
if ( substr_icompare( "@media", str ) ||
substr_icompare( "@import", str ) ||
substr_icompare( "@font-face", str ) ||
substr_icompare( "@supports", str ) ) {
skip_spaces( str );
if ( *str == ')' ) {
str++;
setResult(true);
}
else {
skip_to_next( str, ')', 0 );
}
}
else {
malformed = true;
skip_to_next( str, 0, '{' );
}
}
else { // Not a known function
malformed = true;
skip_to_next( str, 0, '{' );
}
}
};

Expand Down
12 changes: 1 addition & 11 deletions crengine/src/lvtextfm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1851,8 +1851,7 @@ class LVFormatter {
FriBidiLevel newBidiLevel;
#endif
#if (USE_HARFBUZZ==1)
bool checkIfHarfbuzz = true;
bool usingHarfbuzz = false;
bool usingHarfbuzz = m_kerning_mode == KERNING_MODE_HARFBUZZ;
// Unicode script change (note: hb_script_t is uint32_t)
lUInt32 prevScript = HB_SCRIPT_COMMON;
hb_unicode_funcs_t* _hb_unicode_funcs = hb_unicode_funcs_get_default();
Expand All @@ -1874,15 +1873,6 @@ class LVFormatter {
isObject = m_flags[i] & LCHAR_IS_OBJECT; // image, float or inline box
newFont = isObject ? NULL : (LVFont *)newSrc->t.font;
newLetterSpacing = newSrc->letter_spacing; // 0 for objects
#if (USE_HARFBUZZ==1)
// Check if we are using Harfbuzz kerning with the first font met
if ( checkIfHarfbuzz && newFont ) {
if ( m_kerning_mode == KERNING_MODE_HARFBUZZ ) {
usingHarfbuzz = true;
}
checkIfHarfbuzz = false;
}
#endif
}
if (i > 0)
prevCharIsObject = m_flags[i-1] & LCHAR_IS_OBJECT; // image, float or inline box
Expand Down
41 changes: 40 additions & 1 deletion crengine/src/lvxml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2894,6 +2894,7 @@ void LVXMLParser::Reset()
LVTextFileBase::Reset();
m_state = ps_bof;
m_in_cdata = false;
m_in_html_style_tag = false;
m_in_html_script_tag = false;
}

Expand All @@ -2902,6 +2903,7 @@ LVXMLParser::LVXMLParser( LVStreamRef stream, LVXMLParserCallback * callback, bo
, m_callback(callback)
, m_state(0)
, m_in_cdata(false)
, m_in_html_style_tag(false)
, m_in_html_script_tag(false)
, m_trimspaces(true)
, m_citags(false)
Expand Down Expand Up @@ -3106,6 +3108,18 @@ bool LVXMLParser::Parse()
// CRLog::trace("<%s>", LCSTR(tagname) );
if (!bodyStarted && tagname == "body")
bodyStarted = true;
else if ( tagname.length() == 5 &&
( tagname[0] == U'S' || tagname[0] == U's') &&
( tagname[1] == U'T' || tagname[1] == U't') &&
( tagname[2] == U'Y' || tagname[2] == U'y') &&
( tagname[3] == U'L' || tagname[3] == U'l') &&
( tagname[4] == U'E' || tagname[4] == U'e') ) {
// Handle content as text, but don't stop just at any '<',
// only at '</style>', as <style> may contain comments
// (which can contain anything, so tags) and even tags
// (eg. "background-image:url('data:image/svg+xml;utf8,<svg><path...")
m_in_html_style_tag = true;
}
else if ( tagname.length() == 6 &&
( tagname[0] == U'S' || tagname[0] == U's') &&
( tagname[1] == U'C' || tagname[1] == U'c') &&
Expand Down Expand Up @@ -3133,6 +3147,8 @@ bool LVXMLParser::Parse()
// end of tag
if ( ch!='>' ) { // '/' in '<hr/>' : self closing tag
m_callback->OnTagClose(tagns.c_str(), tagname.c_str(), true);
if ( m_in_html_style_tag )
m_in_html_style_tag = false;
if ( m_in_html_script_tag )
m_in_html_script_tag = false;
}
Expand Down Expand Up @@ -3241,6 +3257,9 @@ bool LVXMLParser::Parse()
// regular text after ']]>' until the next '<tag>'
m_state = ps_text;
}
else if ( m_in_html_style_tag ) {
m_in_html_style_tag = false;
}
else if ( m_in_html_script_tag ) {
m_in_html_script_tag = false;
}
Expand Down Expand Up @@ -5776,7 +5795,27 @@ bool LVXMLParser::ReadText()
}
}
else if ( ch=='<' ) {
if ( m_in_html_script_tag ) { // we're done only when we meet </script>
if ( m_in_html_style_tag ) { // we're done only when we meet </style>
if ( ptr + 1 < end ) {
if ( ptr[1] == '/' ) {
if ( ptr + 6 < end ) {
const lChar32 * buf = ptr + 2;
lString32 tag(buf, 5);
if ( tag.lowercase() == U"style" ) {
nbCharToSkipOnFlgBreak = 1;
goto end_of_node;
}
}
else if ( !hasNoMoreData ) {
break;
}
}
}
else if ( !hasNoMoreData ) {
break;
}
}
else if ( m_in_html_script_tag ) { // we're done only when we meet </script>
if ( ptr + 1 < end ) {
if ( ptr[1] == '/' ) {
if ( ptr + 7 < end ) {
Expand Down
Loading