Index: Source/core/rendering/RenderQuote.cpp |
diff --git a/Source/core/rendering/RenderQuote.cpp b/Source/core/rendering/RenderQuote.cpp |
index 6586d0438fdf42c6b2622caf4761d93daa271ae2..9cd2c702e74563752cfe3f45dc53c0175e3eda43 100644 |
--- a/Source/core/rendering/RenderQuote.cpp |
+++ b/Source/core/rendering/RenderQuote.cpp |
@@ -22,10 +22,9 @@ |
#include "config.h" |
#include "core/rendering/RenderQuote.h" |
-#include "core/rendering/RenderView.h" |
-#include <wtf/text/AtomicString.h> |
+#include "core/rendering/style/QuotesData.h" |
-#define U(x) ((const UChar*)L##x) |
+using namespace WTF::Unicode; |
namespace WebCore { |
@@ -35,14 +34,15 @@ RenderQuote::RenderQuote(Document* node, QuoteType quote) |
, m_depth(0) |
, m_next(0) |
, m_previous(0) |
- , m_attached(false) |
+ , m_isAttached(false) |
{ |
} |
RenderQuote::~RenderQuote() |
{ |
- ASSERT(!m_attached); |
- ASSERT(!m_next && !m_previous); |
+ ASSERT(!m_isAttached); |
+ ASSERT(!m_next); |
+ ASSERT(!m_previous); |
} |
void RenderQuote::willBeDestroyed() |
@@ -63,229 +63,323 @@ void RenderQuote::styleDidChange(StyleDifference diff, const RenderStyle* oldSty |
setText(originalText()); |
} |
-typedef HashMap<AtomicString, const QuotesData*, CaseFoldingHash> QuotesMap; |
+const unsigned maxDistinctQuoteCharacters = 16; |
-static const QuotesMap& quotesDataLanguageMap() |
+#if !ASSERT_DISABLED |
+ |
+static void checkNumberOfDistinctQuoteCharacters(UChar character) |
{ |
- DEFINE_STATIC_LOCAL(QuotesMap, staticQuotesMap, ()); |
- if (staticQuotesMap.size()) |
- return staticQuotesMap; |
+ ASSERT(character); |
+ static UChar distinctQuoteCharacters[maxDistinctQuoteCharacters]; |
+ for (unsigned i = 0; i < maxDistinctQuoteCharacters; ++i) { |
+ if (distinctQuoteCharacters[i] == character) |
+ return; |
+ if (!distinctQuoteCharacters[i]) { |
+ distinctQuoteCharacters[i] = character; |
+ return; |
+ } |
+ } |
+ ASSERT_NOT_REACHED(); |
+} |
+ |
+#endif |
+ |
+struct QuotesForLanguage { |
+ const char* language; |
+ UChar open1; |
+ UChar close1; |
+ UChar open2; |
+ UChar close2; |
+}; |
+static int quoteTableLanguageComparisonFunction(const void* a, const void* b) |
+{ |
+ return strcmp(static_cast<const QuotesForLanguage*>(a)->language, |
+ static_cast<const QuotesForLanguage*>(b)->language); |
+} |
+ |
+static const QuotesForLanguage* quotesForLanguage(const String& language) |
+{ |
// Table of quotes from http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#quotes |
- #define QUOTES_LANG(lang, o1, c1, o2, c2) staticQuotesMap.set(lang, QuotesData::create(U(o1), U(c1), U(o2), U(c2)).leakRef()) |
- QUOTES_LANG("af", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("agq", "\x201e", "\x201d", "\x201a", "\x2019"); |
- QUOTES_LANG("ak", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("am", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("ar", "\x201d", "\x201c", "\x2019", "\x2018"); |
- QUOTES_LANG("asa", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("az-Cyrl", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("bas", "\x00ab", "\x00bb", "\x201e", "\x201c"); |
- QUOTES_LANG("bem", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("bez", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("bg", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("bm", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("bn", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("br", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("brx", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("bs-Cyrl", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("ca", "\x201c", "\x201d", "\x00ab", "\x00bb"); |
- QUOTES_LANG("cgg", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("chr", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("cs", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("da", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("dav", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("de", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("de-CH", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("dje", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("dua", "\x00ab", "\x00bb", "\x2018", "\x2019"); |
- QUOTES_LANG("dyo", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("dz", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ebu", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ee", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("el", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("en", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("en-GB", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("es", "\x201c", "\x201d", "\x00ab", "\x00bb"); |
- QUOTES_LANG("et", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("eu", "\x201c", "\x201d", "\x00ab", "\x00bb"); |
- QUOTES_LANG("ewo", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("fa", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("ff", "\x201e", "\x201d", "\x201a", "\x2019"); |
- QUOTES_LANG("fi", "\x201d", "\x201d", "\x2019", "\x2019"); |
- QUOTES_LANG("fr", "\x00ab", "\x00bb", "\x00ab", "\x00bb"); |
- QUOTES_LANG("fr-CA", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("fr-CH", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("gsw", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("gu", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("guz", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ha", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("he", "\x0022", "\x0022", "\x0027", "\x0027"); |
- QUOTES_LANG("hi", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("hr", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("hu", "\x201e", "\x201d", "\x00bb", "\x00ab"); |
- QUOTES_LANG("id", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ig", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("it", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("ja", "\x300c", "\x300d", "\x300e", "\x300f"); |
- QUOTES_LANG("jgo", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("jmc", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("kab", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("kam", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("kde", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("kea", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("khq", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ki", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("kkj", "\x00ab", "\x00bb", "\x2039", "\x203a"); |
- QUOTES_LANG("kln", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("km", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("kn", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ko", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ksb", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ksf", "\x00ab", "\x00bb", "\x2018", "\x2019"); |
- QUOTES_LANG("lag", "\x201d", "\x201d", "\x2019", "\x2019"); |
- QUOTES_LANG("lg", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ln", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("lo", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("lt", "\x201e", "\x201c", "\x201e", "\x201c"); |
- QUOTES_LANG("lu", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("luo", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("luy", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("lv", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mas", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mer", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mfe", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mg", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("mgo", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mk", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("ml", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mr", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ms", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("mua", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("my", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("naq", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("nb", "\x00ab", "\x00bb", "\x2018", "\x2019"); |
- QUOTES_LANG("nd", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("nl", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("nmg", "\x201e", "\x201d", "\x00ab", "\x00bb"); |
- QUOTES_LANG("nn", "\x00ab", "\x00bb", "\x2018", "\x2019"); |
- QUOTES_LANG("nnh", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("nus", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("nyn", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("pl", "\x201e", "\x201d", "\x00ab", "\x00bb"); |
- QUOTES_LANG("pt", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("pt-PT", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("rn", "\x201d", "\x201d", "\x2019", "\x2019"); |
- QUOTES_LANG("ro", "\x201e", "\x201d", "\x00ab", "\x00bb"); |
- QUOTES_LANG("rof", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ru", "\x00ab", "\x00bb", "\x201e", "\x201c"); |
- QUOTES_LANG("rw", "\x00ab", "\x00bb", "\x2018", "\x2019"); |
- QUOTES_LANG("rwk", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("saq", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("sbp", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("seh", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ses", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("sg", "\x00ab", "\x00bb", "\x201c", "\x201d"); |
- QUOTES_LANG("shi", "\x00ab", "\x00bb", "\x201e", "\x201d"); |
- QUOTES_LANG("shi-Tfng", "\x00ab", "\x00bb", "\x201e", "\x201d"); |
- QUOTES_LANG("si", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("sk", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("sl", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("sn", "\x201d", "\x201d", "\x2019", "\x2019"); |
- QUOTES_LANG("so", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("sq", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("sr", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("sr-Latn", "\x201e", "\x201c", "\x201a", "\x2018"); |
- QUOTES_LANG("sv", "\x201d", "\x201d", "\x2019", "\x2019"); |
- QUOTES_LANG("sw", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("swc", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ta", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("te", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("teo", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("th", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("ti-ER", "\x2018", "\x2019", "\x201c", "\x201d"); |
- QUOTES_LANG("to", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("tr", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("twq", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("tzm", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("uk", "\x00ab", "\x00bb", "\x201e", "\x201c"); |
- QUOTES_LANG("ur", "\x201d", "\x201c", "\x2019", "\x2018"); |
- QUOTES_LANG("vai", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("vai-Latn", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("vi", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("vun", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("xh", "\x2018", "\x2019", "\x201c", "\x201d"); |
- QUOTES_LANG("xog", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("yav", "\x00ab", "\x00bb", "\x00ab", "\x00bb"); |
- QUOTES_LANG("yo", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("zh", "\x201c", "\x201d", "\x2018", "\x2019"); |
- QUOTES_LANG("zh-Hant", "\x300c", "\x300d", "\x300e", "\x300f"); |
- QUOTES_LANG("zu", "\x201c", "\x201d", "\x2018", "\x2019"); |
- #undef QUOTES_LANG |
- |
- return staticQuotesMap; |
+ static const QuotesForLanguage quoteTable[] = { |
+ { "af", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "agq", 0x201e, 0x201d, 0x201a, 0x2019 }, |
+ { "ak", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "am", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "ar", 0x201d, 0x201c, 0x2019, 0x2018 }, |
+ { "asa", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "az-cyrl", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "bas", 0x00ab, 0x00bb, 0x201e, 0x201c }, |
+ { "bem", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "bez", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "bg", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "bm", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "bn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "br", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "brx", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "bs-cyrl", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "ca", 0x201c, 0x201d, 0x00ab, 0x00bb }, |
+ { "cgg", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "chr", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "cs", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "da", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "dav", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "de", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "de-ch", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "dje", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "dua", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
+ { "dyo", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "dz", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ebu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ee", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "el", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "en", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "en-gb", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "es", 0x201c, 0x201d, 0x00ab, 0x00bb }, |
+ { "et", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "eu", 0x201c, 0x201d, 0x00ab, 0x00bb }, |
+ { "ewo", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "fa", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "ff", 0x201e, 0x201d, 0x201a, 0x2019 }, |
+ { "fi", 0x201d, 0x201d, 0x2019, 0x2019 }, |
+ { "fr", 0x00ab, 0x00bb, 0x00ab, 0x00bb }, |
+ { "fr-ca", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "fr-ch", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "gsw", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "gu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "guz", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ha", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "he", 0x0022, 0x0022, 0x0027, 0x0027 }, |
+ { "hi", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "hr", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "hu", 0x201e, 0x201d, 0x00bb, 0x00ab }, |
+ { "id", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ig", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "it", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "ja", 0x300c, 0x300d, 0x300e, 0x300f }, |
+ { "jgo", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "jmc", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "kab", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "kam", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "kde", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "kea", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "khq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ki", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "kkj", 0x00ab, 0x00bb, 0x2039, 0x203a }, |
+ { "kln", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "km", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "kn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ko", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ksb", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ksf", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
+ { "lag", 0x201d, 0x201d, 0x2019, 0x2019 }, |
+ { "lg", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ln", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "lo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "lt", 0x201e, 0x201c, 0x201e, 0x201c }, |
+ { "lu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "luo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "luy", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "lv", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mas", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mer", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mfe", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mg", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "mgo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mk", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "ml", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mr", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ms", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "mua", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "my", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "naq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "nb", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
+ { "nd", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "nl", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "nmg", 0x201e, 0x201d, 0x00ab, 0x00bb }, |
+ { "nn", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
+ { "nnh", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "nus", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "nyn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "pl", 0x201e, 0x201d, 0x00ab, 0x00bb }, |
+ { "pt", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "pt-pt", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "rn", 0x201d, 0x201d, 0x2019, 0x2019 }, |
+ { "ro", 0x201e, 0x201d, 0x00ab, 0x00bb }, |
+ { "rof", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ru", 0x00ab, 0x00bb, 0x201e, 0x201c }, |
+ { "rw", 0x00ab, 0x00bb, 0x2018, 0x2019 }, |
+ { "rwk", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "saq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "sbp", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "seh", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ses", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "sg", 0x00ab, 0x00bb, 0x201c, 0x201d }, |
+ { "shi", 0x00ab, 0x00bb, 0x201e, 0x201d }, |
+ { "shi-tfng", 0x00ab, 0x00bb, 0x201e, 0x201d }, |
+ { "si", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "sk", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "sl", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "sn", 0x201d, 0x201d, 0x2019, 0x2019 }, |
+ { "so", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "sq", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "sr", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "sr-latn", 0x201e, 0x201c, 0x201a, 0x2018 }, |
+ { "sv", 0x201d, 0x201d, 0x2019, 0x2019 }, |
+ { "sw", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "swc", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ta", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "te", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "teo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "th", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "ti-er", 0x2018, 0x2019, 0x201c, 0x201d }, |
+ { "to", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "tr", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "twq", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "tzm", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "uk", 0x00ab, 0x00bb, 0x201e, 0x201c }, |
+ { "ur", 0x201d, 0x201c, 0x2019, 0x2018 }, |
+ { "vai", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "vai-latn", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "vi", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "vun", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "xh", 0x2018, 0x2019, 0x201c, 0x201d }, |
+ { "xog", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "yav", 0x00ab, 0x00bb, 0x00ab, 0x00bb }, |
+ { "yo", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "zh", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ { "zh-hant", 0x300c, 0x300d, 0x300e, 0x300f }, |
+ { "zu", 0x201c, 0x201d, 0x2018, 0x2019 }, |
+ }; |
+ |
+ const unsigned maxLanguageLength = 8; |
+ |
+#if !ASSERT_DISABLED |
+ // One time check that the table meets the constraints that the code below relies on. |
+ |
+ static bool didOneTimeCheck = false; |
+ if (!didOneTimeCheck) { |
+ didOneTimeCheck = true; |
+ |
+ checkNumberOfDistinctQuoteCharacters(quotationMark); |
+ checkNumberOfDistinctQuoteCharacters(apostrophe); |
+ |
+ for (unsigned i = 0; i < WTF_ARRAY_LENGTH(quoteTable); ++i) { |
+ ASSERT(strlen(quoteTable[i].language) <= maxLanguageLength); |
+ |
+ if (i) |
+ ASSERT(strcmp(quoteTable[i - 1].language, quoteTable[i].language) < 0); |
+ |
+ for (unsigned j = 0; UChar character = quoteTable[i].language[j]; ++j) |
+ ASSERT(isASCIILower(character) || character == '-'); |
+ |
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].open1); |
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].close1); |
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].open2); |
+ checkNumberOfDistinctQuoteCharacters(quoteTable[i].close2); |
+ } |
+ } |
+#endif |
+ |
+ unsigned length = language.length(); |
+ if (!length || length > maxLanguageLength) |
+ return 0; |
+ |
+ char languageKeyBuffer[maxLanguageLength + 1]; |
+ for (unsigned i = 0; i < length; ++i) { |
+ UChar character = toASCIILower(language[i]); |
+ if (!(isASCIILower(character) || character == '-')) |
+ return 0; |
+ languageKeyBuffer[i] = static_cast<char>(character); |
+ } |
+ languageKeyBuffer[length] = 0; |
+ |
+ QuotesForLanguage languageKey = { languageKeyBuffer, 0, 0, 0, 0 }; |
+ |
+ return static_cast<const QuotesForLanguage*>(bsearch(&languageKey, |
+ quoteTable, WTF_ARRAY_LENGTH(quoteTable), sizeof(quoteTable[0]), quoteTableLanguageComparisonFunction)); |
} |
-static const QuotesData* basicQuotesData() |
+static StringImpl* stringForQuoteCharacter(UChar character) |
{ |
- // FIXME: The default quotes should be the fancy quotes for "en". |
- static const QuotesData* staticBasicQuotes = QuotesData::create(U("\""), U("\""), U("'"), U("'")).leakRef(); |
- return staticBasicQuotes; |
+ // Use linear search because there is a small number of distinct characters, thus binary search is unneeded. |
+ ASSERT(character); |
+ struct StringForCharacter { |
+ UChar character; |
+ StringImpl* string; |
+ }; |
+ static StringForCharacter strings[maxDistinctQuoteCharacters]; |
+ for (unsigned i = 0; i < maxDistinctQuoteCharacters; ++i) { |
+ if (strings[i].character == character) |
+ return strings[i].string; |
+ if (!strings[i].character) { |
+ strings[i].character = character; |
+ strings[i].string = StringImpl::create8BitIfPossible(&character, 1).leakRef(); |
+ return strings[i].string; |
+ } |
+ } |
+ ASSERT_NOT_REACHED(); |
+ return StringImpl::empty(); |
+} |
+ |
+static inline StringImpl* quotationMarkString() |
+{ |
+ static StringImpl* quotationMarkString = stringForQuoteCharacter(quotationMark); |
+ return quotationMarkString; |
+} |
+ |
+static inline StringImpl* apostropheString() |
+{ |
+ static StringImpl* apostropheString = stringForQuoteCharacter(apostrophe); |
+ return apostropheString; |
} |
PassRefPtr<StringImpl> RenderQuote::originalText() const |
{ |
+ if (m_depth < 0) |
+ return StringImpl::empty(); |
+ bool isOpenQuote = false; |
switch (m_type) { |
case NO_OPEN_QUOTE: |
case NO_CLOSE_QUOTE: |
return StringImpl::empty(); |
- case CLOSE_QUOTE: |
- return quotesData()->getCloseQuote(m_depth - 1).impl(); |
case OPEN_QUOTE: |
- return quotesData()->getOpenQuote(m_depth).impl(); |
+ isOpenQuote = true; |
+ // fall through |
+ case CLOSE_QUOTE: |
+ if (const QuotesData* quotes = style()->quotes()) |
+ return isOpenQuote ? quotes->openQuote(m_depth).impl() : quotes->closeQuote(m_depth).impl(); |
+ if (const QuotesForLanguage* quotes = quotesForLanguage(style()->locale())) |
+ return stringForQuoteCharacter(isOpenQuote ? (m_depth ? quotes->open2 : quotes->open1) : (m_depth ? quotes->close2 : quotes->close1)); |
+ // FIXME: Should the default be the quotes for "en" rather than straight quotes? |
+ return m_depth ? apostropheString() : quotationMarkString(); |
} |
ASSERT_NOT_REACHED(); |
return StringImpl::empty(); |
} |
-const QuotesData* RenderQuote::quotesData() const |
-{ |
- if (QuotesData* customQuotes = style()->quotes()) |
- return customQuotes; |
- |
- AtomicString language = style()->locale(); |
- if (language.isNull()) |
- return basicQuotesData(); |
- const QuotesData* quotes = quotesDataLanguageMap().get(language); |
- if (!quotes) |
- return basicQuotesData(); |
- return quotes; |
-} |
- |
void RenderQuote::attachQuote() |
{ |
ASSERT(view()); |
- ASSERT(!m_attached); |
- ASSERT(!m_next && !m_previous); |
+ ASSERT(!m_isAttached); |
+ ASSERT(!m_next); |
+ ASSERT(!m_previous); |
ASSERT(isRooted()); |
- if (!view()->renderQuoteHead()) { |
- view()->setRenderQuoteHead(this); |
- m_attached = true; |
- return; |
- } |
- |
- for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) { |
- // Skip unattached predecessors to avoid having stale m_previous pointers |
- // if the previous node is never attached and is then destroyed. |
- if (!predecessor->isQuote() || !toRenderQuote(predecessor)->isAttached()) |
- continue; |
- m_previous = toRenderQuote(predecessor); |
- m_next = m_previous->m_next; |
- m_previous->m_next = this; |
- if (m_next) |
- m_next->m_previous = this; |
- break; |
+ // Optimize case where this is the first quote in a RenderView by not searching for predecessors in that case. |
+ if (view()->renderQuoteHead()) { |
+ for (RenderObject* predecessor = previousInPreOrder(); predecessor; predecessor = predecessor->previousInPreOrder()) { |
+ // Skip unattached predecessors to avoid having stale m_previous pointers |
+ // if the previous node is never attached and is then destroyed. |
+ if (!predecessor->isQuote() || !toRenderQuote(predecessor)->m_isAttached) |
+ continue; |
+ m_previous = toRenderQuote(predecessor); |
+ m_next = m_previous->m_next; |
+ m_previous->m_next = this; |
+ if (m_next) |
+ m_next->m_previous = this; |
+ break; |
+ } |
} |
if (!m_previous) { |
@@ -294,22 +388,22 @@ void RenderQuote::attachQuote() |
if (m_next) |
m_next->m_previous = this; |
} |
- m_attached = true; |
+ m_isAttached = true; |
for (RenderQuote* quote = this; quote; quote = quote->m_next) |
quote->updateDepth(); |
- ASSERT(!m_next || m_next->m_attached); |
+ ASSERT(!m_next || m_next->m_isAttached); |
ASSERT(!m_next || m_next->m_previous == this); |
- ASSERT(!m_previous || m_previous->m_attached); |
+ ASSERT(!m_previous || m_previous->m_isAttached); |
ASSERT(!m_previous || m_previous->m_next == this); |
} |
void RenderQuote::detachQuote() |
{ |
- ASSERT(!m_next || m_next->m_attached); |
- ASSERT(!m_previous || m_previous->m_attached); |
- if (!m_attached) |
+ ASSERT(!m_next || m_next->m_isAttached); |
+ ASSERT(!m_previous || m_previous->m_isAttached); |
+ if (!m_isAttached) |
return; |
if (m_previous) |
m_previous->m_next = m_next; |
@@ -321,7 +415,7 @@ void RenderQuote::detachQuote() |
for (RenderQuote* quote = m_next; quote; quote = quote->m_next) |
quote->updateDepth(); |
} |
- m_attached = false; |
+ m_isAttached = false; |
m_next = 0; |
m_previous = 0; |
m_depth = 0; |
@@ -329,7 +423,7 @@ void RenderQuote::detachQuote() |
void RenderQuote::updateDepth() |
{ |
- ASSERT(m_attached); |
+ ASSERT(m_isAttached); |
int oldDepth = m_depth; |
m_depth = 0; |
if (m_previous) { |