X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b1a3a964997a143de68f2e3c75fa8dd82a4e3361..64ea838d8f4d1853b7d850db93ee565e901d099a:/src/html/htmltag.cpp diff --git a/src/html/htmltag.cpp b/src/html/htmltag.cpp index 4365a26554..7bf1fa8d2e 100644 --- a/src/html/htmltag.cpp +++ b/src/html/htmltag.cpp @@ -23,6 +23,8 @@ #endif #include "wx/html/htmlpars.h" +#include "wx/html/styleparams.h" + #include "wx/vector.h" #include // for vsscanf @@ -63,14 +65,14 @@ class wxHtmlTagsCacheData : public wxVector bool wxIsCDATAElement(const wxChar *tag) { - return (wxStrcmp(tag, _T("SCRIPT")) == 0) || - (wxStrcmp(tag, _T("STYLE")) == 0); + return (wxStrcmp(tag, wxT("SCRIPT")) == 0) || + (wxStrcmp(tag, wxT("STYLE")) == 0); } bool wxIsCDATAElement(const wxString& tag) { - return (wxStrcmp(tag.wx_str(), wxSTRING_TEXT("SCRIPT")) == 0) || - (wxStrcmp(tag.wx_str(), wxSTRING_TEXT("STYLE")) == 0); + return (wxStrcmp(tag.wx_str(), wxS("SCRIPT")) == 0) || + (wxStrcmp(tag.wx_str(), wxS("STYLE")) == 0); } wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source) @@ -83,118 +85,132 @@ wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source) const wxString::const_iterator end = source.end(); for ( wxString::const_iterator pos = source.begin(); pos < end; ++pos ) { - if (*pos == wxT('<')) // tag found: - { - // don't cache comment tags - if ( wxHtmlParser::SkipCommentTag(pos, source.end()) ) - continue; + if (*pos != wxT('<')) + continue; - size_t tg = Cache().size(); - Cache().push_back(wxHtmlCacheItem()); + // possible tag start found: - wxString::const_iterator stpos = pos++; - Cache()[tg].Key = stpos; + // don't cache comment tags + if ( wxHtmlParser::SkipCommentTag(pos, end) ) + continue; - int i; - for ( i = 0; - pos < end && i < (int)WXSIZEOF(tagBuffer) - 1 && - *pos != wxT('>') && !wxIsspace(*pos); - ++i, ++pos ) - { - tagBuffer[i] = (wxChar)wxToupper(*pos); - } - tagBuffer[i] = _T('\0'); + // Remember the starting tag position. + wxString::const_iterator stpos = pos++; + + // And look for the ending one. + int i; + for ( i = 0; + pos < end && i < (int)WXSIZEOF(tagBuffer) - 1 && + *pos != wxT('>') && !wxIsspace(*pos); + ++i, ++pos ) + { + tagBuffer[i] = (wxChar)wxToupper(*pos); + } + tagBuffer[i] = wxT('\0'); - Cache()[tg].Name = new wxChar[i+1]; - memcpy(Cache()[tg].Name, tagBuffer, (i+1)*sizeof(wxChar)); + while (pos < end && *pos != wxT('>')) + ++pos; - while (pos < end && *pos != wxT('>')) - ++pos; + if ( pos == end ) + { + // We didn't find a closing bracket, this is not a valid tag after + // all. Notice that we need to roll back pos to avoid creating an + // invalid iterator when "++pos" is done in the loop statement. + --pos; + + continue; + } + + // We have a valid tag, add it to the cache. + size_t tg = Cache().size(); + Cache().push_back(wxHtmlCacheItem()); + Cache()[tg].Key = stpos; + Cache()[tg].Name = new wxChar[i+1]; + memcpy(Cache()[tg].Name, tagBuffer, (i+1)*sizeof(wxChar)); - if ((stpos+1) < end && *(stpos+1) == wxT('/')) // ending tag: + if ((stpos+1) < end && *(stpos+1) == wxT('/')) // ending tag: + { + Cache()[tg].type = wxHtmlCacheItem::Type_EndingTag; + // find matching begin tag: + for (i = tg; i >= 0; i--) { - Cache()[tg].type = wxHtmlCacheItem::Type_EndingTag; - // find matching begin tag: - for (i = tg; i >= 0; i--) + if ((Cache()[i].type == wxHtmlCacheItem::Type_NoMatchingEndingTag) && (wxStrcmp(Cache()[i].Name, tagBuffer+1) == 0)) { - if ((Cache()[i].type == wxHtmlCacheItem::Type_NoMatchingEndingTag) && (wxStrcmp(Cache()[i].Name, tagBuffer+1) == 0)) - { - Cache()[i].type = wxHtmlCacheItem::Type_Normal; - Cache()[i].End1 = stpos; - Cache()[i].End2 = pos + 1; - break; - } + Cache()[i].type = wxHtmlCacheItem::Type_Normal; + Cache()[i].End1 = stpos; + Cache()[i].End2 = pos + 1; + break; } } - else - { - Cache()[tg].type = wxHtmlCacheItem::Type_NoMatchingEndingTag; + } + else + { + Cache()[tg].type = wxHtmlCacheItem::Type_NoMatchingEndingTag; - if (wxIsCDATAElement(tagBuffer)) + if (wxIsCDATAElement(tagBuffer)) + { + // store the orig pos in case we are missing the closing + // tag (see below) + const wxString::const_iterator old_pos = pos; + bool foundCloseTag = false; + + // find next matching tag + int tag_len = wxStrlen(tagBuffer); + while (pos < end) { - // store the orig pos in case we are missing the closing - // tag (see below) - const wxString::const_iterator old_pos = pos; - bool foundCloseTag = false; - - // find next matching tag - int tag_len = wxStrlen(tagBuffer); - while (pos < end) + // find the ending tag + while (pos + 1 < end && + (*pos != '<' || *(pos+1) != '/')) + ++pos; + if (*pos == '<') + ++pos; + + // see if it matches + int match_pos = 0; + while (pos < end && match_pos < tag_len ) { - // find the ending tag - while (pos + 1 < end && - (*pos != '<' || *(pos+1) != '/')) - ++pos; - if (*pos == '<') - ++pos; - - // see if it matches - int match_pos = 0; - while (pos < end && match_pos < tag_len ) + wxChar c = *pos; + if ( c == '>' || c == '<' ) + break; + + // cast to wxChar needed to suppress warning in + // Unicode build + if ((wxChar)wxToupper(c) == tagBuffer[match_pos]) { - wxChar c = *pos; - if ( c == '>' || c == '<' ) - break; - - // cast to wxChar needed to suppress warning in - // Unicode build - if ((wxChar)wxToupper(c) == tagBuffer[match_pos]) - { - ++match_pos; - } - else if (c == wxT(' ') || c == wxT('\n') || - c == wxT('\r') || c == wxT('\t')) - { - // need to skip over these - } - else - { - match_pos = 0; - } - ++pos; + ++match_pos; } - - // found a match - if (match_pos == tag_len) + else if (c == wxT(' ') || c == wxT('\n') || + c == wxT('\r') || c == wxT('\t')) { - pos = pos - tag_len - 3; - foundCloseTag = true; - break; + // need to skip over these } - else // keep looking for the closing tag + else { - ++pos; + match_pos = 0; } + ++pos; + } + + // found a match + if (match_pos == tag_len) + { + pos = pos - tag_len - 3; + foundCloseTag = true; + break; } - if (!foundCloseTag) + else // keep looking for the closing tag { - // we didn't find closing tag; this means the markup - // is incorrect and the best thing we can do is to - // ignore the unclosed tag and continue parsing as if - // it didn't exist: - pos = old_pos; + ++pos; } } + if (!foundCloseTag) + { + // we didn't find closing tag; this means the markup + // is incorrect and the best thing we can do is to + // ignore the unclosed tag and continue parsing as if + // it didn't exist: + pos = old_pos; + } } } } @@ -203,8 +219,7 @@ wxHtmlTagsCache::wxHtmlTagsCache(const wxString& source) for ( wxHtmlTagsCacheData::iterator i = Cache().begin(); i != Cache().end(); ++i ) { - delete[] i->Name; - i->Name = NULL; + wxDELETEA(i->Name); } } @@ -220,7 +235,12 @@ void wxHtmlTagsCache::QueryTag(const wxString::const_iterator& at, bool *hasEnding) { if (Cache().empty()) + { + *end1 = + *end2 = inputEnd; + *hasEnding = true; return; + } if (Cache()[m_CachePos].Key != at) { @@ -246,9 +266,27 @@ void wxHtmlTagsCache::QueryTag(const wxString::const_iterator& at, } while (Cache()[m_CachePos].Key != at); } - *end1 = Cache()[m_CachePos].End1; - *end2 = Cache()[m_CachePos].End2; - *hasEnding = (Cache()[m_CachePos].type == wxHtmlCacheItem::Type_Normal); + + switch ( Cache()[m_CachePos].type ) + { + case wxHtmlCacheItem::Type_Normal: + *end1 = Cache()[m_CachePos].End1; + *end2 = Cache()[m_CachePos].End2; + *hasEnding = true; + break; + + case wxHtmlCacheItem::Type_EndingTag: + wxFAIL_MSG("QueryTag called for ending tag - can't be"); + // but if it does happen, fall through, better than crashing + + case wxHtmlCacheItem::Type_NoMatchingEndingTag: + // If input HTML is invalid and there's no closing tag for this + // one, pretend that it runs all the way to the end of input + *end1 = inputEnd; + *end2 = inputEnd; + *hasEnding = false; + break; + } } @@ -284,7 +322,7 @@ wxHtmlTag::wxHtmlTag(wxHtmlTag *parent, /* Find parameters and their values: */ - wxChar c; + wxChar c wxDUMMY_INITIALIZE(0); // fill-in name, params and begin pos: wxString::const_iterator i(pos+1); @@ -293,7 +331,7 @@ wxHtmlTag::wxHtmlTag(wxHtmlTag *parent, while ((i < end_pos) && ((c = *(i++)) != wxT(' ') && c != wxT('\r') && c != wxT('\n') && c != wxT('\t') && - c != wxT('>'))) + c != wxT('>') && c != wxT('/'))) { if ((c >= wxT('a')) && (c <= wxT('z'))) c -= (wxT('a') - wxT('A')); @@ -412,6 +450,33 @@ wxHtmlTag::wxHtmlTag(wxHtmlTag *parent, #if WXWIN_COMPATIBILITY_2_8 m_sourceStart = source->begin(); #endif + + // Try to parse any style parameters that can be handled simply by + // converting them to the equivalent HTML 3 attributes: this is a far cry + // from perfect but better than nothing. + static const struct EquivAttr + { + const char *style; + const char *attr; + } equivAttrs[] = + { + { "text-align", "ALIGN" }, + { "width", "WIDTH" }, + { "vertical-align", "VALIGN" }, + { "background", "BGCOLOR" }, + { "background-color", "BGCOLOR" }, + }; + + wxHtmlStyleParams styleParams(*this); + for ( unsigned n = 0; n < WXSIZEOF(equivAttrs); n++ ) + { + const EquivAttr& ea = equivAttrs[n]; + if ( styleParams.HasParam(ea.style) && !HasParam(ea.attr) ) + { + m_ParamNames.Add(ea.attr); + m_ParamValues.Add(styleParams.GetParam(ea.style)); + } + } } wxHtmlTag::~wxHtmlTag() @@ -431,12 +496,12 @@ bool wxHtmlTag::HasParam(const wxString& par) const return (m_ParamNames.Index(par, false) != wxNOT_FOUND); } -wxString wxHtmlTag::GetParam(const wxString& par, bool with_commas) const +wxString wxHtmlTag::GetParam(const wxString& par, bool with_quotes) const { int index = m_ParamNames.Index(par, false); if (index == wxNOT_FOUND) return wxGetEmptyString(); - if (with_commas) + if (with_quotes) { // VS: backward compatibility, seems to be never used by wxHTML... wxString s; @@ -463,17 +528,16 @@ int wxHtmlTag::ScanParam(const wxString& par, return wxSscanf(parval, format, param); } -bool wxHtmlTag::GetParamAsColour(const wxString& par, wxColour *clr) const +/* static */ +bool wxHtmlTag::ParseAsColour(const wxString& str, wxColour *clr) { - wxCHECK_MSG( clr, false, _T("invalid colour argument") ); - - wxString str = GetParam(par); + wxCHECK_MSG( clr, false, wxT("invalid colour argument") ); // handle colours defined in HTML 4.0 first: - if (str.length() > 1 && str[0] != _T('#')) + if (str.length() > 1 && str[0] != wxT('#')) { - #define HTML_COLOUR(name, r, g, b) \ - if (str.IsSameAs(wxSTRING_TEXT(name), false)) \ + #define HTML_COLOUR(name, r, g, b) \ + if (str.IsSameAs(wxS(name), false)) \ { clr->Set(r, g, b); return true; } HTML_COLOUR("black", 0x00,0x00,0x00) HTML_COLOUR("silver", 0xC0,0xC0,0xC0) @@ -504,13 +568,23 @@ bool wxHtmlTag::GetParamAsColour(const wxString& par, wxColour *clr) const return false; } +bool wxHtmlTag::GetParamAsColour(const wxString& par, wxColour *clr) const +{ + const wxString str = GetParam(par); + return !str.empty() && ParseAsColour(str, clr); +} + bool wxHtmlTag::GetParamAsInt(const wxString& par, int *clr) const { - if (!HasParam(par)) return false; + if ( !HasParam(par) ) + return false; + long i; - bool succ = GetParam(par).ToLong(&i); + if ( !GetParam(par).ToLong(&i) ) + return false; + *clr = (int)i; - return succ; + return true; } wxString wxHtmlTag::GetAllParams() const