Bug 234485: Map xml:lang attribute into style so that it's used for font selection and hyphenation. r=bzbarsky

The code in nsHTMLStyleSheet implements LangRule to map xml:lang into
style and the code to manage its uniqueness.

The change to nsGenericHTMLElement fixes the mapping of the HTML lang
attribute to do cascading the way all other rule mapping does so that
the cascading works correctly.

The tests test that the correct style language is used for hyphenation
by copying over a set of hyphenation reftests that check its basic
response to languages.  There are no specific tests for font selection,
but font selection is known to use the same language data from style.

I verified manually (see other attachments to bug) that the rule
uniqueness is being managed correctly.

--HG--
rename : layout/reftests/text/auto-hyphenation-1.html => layout/reftests/text/auto-hyphenation-xmllang-1.xhtml
rename : layout/reftests/text/auto-hyphenation-10.html => layout/reftests/text/auto-hyphenation-xmllang-10.xhtml
rename : layout/reftests/text/auto-hyphenation-1.html => layout/reftests/text/auto-hyphenation-xmllang-11a.xhtml
rename : layout/reftests/text/auto-hyphenation-1.html => layout/reftests/text/auto-hyphenation-xmllang-11b.xhtml
rename : layout/reftests/text/auto-hyphenation-4.html => layout/reftests/text/auto-hyphenation-xmllang-12a.xhtml
rename : layout/reftests/text/auto-hyphenation-4.html => layout/reftests/text/auto-hyphenation-xmllang-12b.xhtml
rename : layout/reftests/text/auto-hyphenation-1.html => layout/reftests/text/auto-hyphenation-xmllang-13a.xhtml
rename : layout/reftests/text/auto-hyphenation-1.html => layout/reftests/text/auto-hyphenation-xmllang-13b.xhtml
rename : layout/reftests/text/auto-hyphenation-4.html => layout/reftests/text/auto-hyphenation-xmllang-14a.xhtml
rename : layout/reftests/text/auto-hyphenation-4.html => layout/reftests/text/auto-hyphenation-xmllang-14b.xhtml
rename : layout/reftests/text/auto-hyphenation-1a.html => layout/reftests/text/auto-hyphenation-xmllang-1a.xhtml
rename : layout/reftests/text/auto-hyphenation-2.html => layout/reftests/text/auto-hyphenation-xmllang-2.xhtml
rename : layout/reftests/text/auto-hyphenation-3.html => layout/reftests/text/auto-hyphenation-xmllang-3.xhtml
rename : layout/reftests/text/auto-hyphenation-4.html => layout/reftests/text/auto-hyphenation-xmllang-4.xhtml
rename : layout/reftests/text/auto-hyphenation-5.html => layout/reftests/text/auto-hyphenation-xmllang-5.xhtml
rename : layout/reftests/text/auto-hyphenation-6.html => layout/reftests/text/auto-hyphenation-xmllang-6.xhtml
rename : layout/reftests/text/auto-hyphenation-7.html => layout/reftests/text/auto-hyphenation-xmllang-7.xhtml
rename : layout/reftests/text/auto-hyphenation-8.html => layout/reftests/text/auto-hyphenation-xmllang-8.xhtml
rename : layout/reftests/text/auto-hyphenation-9.html => layout/reftests/text/auto-hyphenation-xmllang-9.xhtml
This commit is contained in:
L. David Baron 2013-05-30 16:00:20 +08:00
parent c18b9f7a1a
commit b31121a2a1
23 changed files with 414 additions and 5 deletions

View File

@ -1461,10 +1461,12 @@ nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttribu
}
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::lang);
if (value && value->Type() == nsAttrValue::eString) {
aData->ValueForLang()->SetStringValue(value->GetStringValue(),
eCSSUnit_Ident);
nsCSSValue* lang = aData->ValueForLang();
if (lang->GetUnit() == eCSSUnit_Null) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::lang);
if (value && value->Type() == nsAttrValue::eString) {
lang->SetStringValue(value->GetStringValue(), eCSSUnit_Ident);
}
}
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- simple test for automatic hyphenation -->
<body xml:lang="en-us">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that hyphenation is not applied when language is not specified -->
<body>
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that xml:lang beats lang -->
<body xml:lang="en-us" lang="x-unknown-language">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that xml:lang beats lang -->
<body lang="x-unknown-language" xml:lang="en-us">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that xml:lang beats lang -->
<!-- check that hyphenation is not applied to unknown language -->
<body xml:lang="x-unknown-language" lang="en-us">
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that xml:lang beats lang -->
<!-- check that hyphenation is not applied to unknown language -->
<body lang="en-us" xml:lang="x-unknown-language">
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that innermost beats xml:lang vs. lang difference -->
<body lang="x-unknown-language">
<div xml:lang="en-us">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
supercalifragilisticexpialidocious
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that innermost beats xml:lang vs. lang difference -->
<body xml:lang="x-unknown-language">
<div lang="en-us">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
supercalifragilisticexpialidocious
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that innermost beats xml:lang vs. lang difference -->
<!-- check that hyphenation is not applied to unknown language -->
<body lang="en-us">
<div xml:lang="x-unknown-language">
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that innermost beats xml:lang vs. lang difference -->
<!-- check that hyphenation is not applied to unknown language -->
<body xml:lang="en-us">
<div lang="x-unknown-language">
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- adding random <span>s should not affect hyphenation -->
<body xml:lang="en-us">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
super<span>cali</span>frag<span>ili</span>sti<span>cex</span>pialidoc<span>i</span>ous
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- mixed languages in a word should inhibit automatic hyphenation -->
<body xml:lang="en-us">
<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
supercalifragilisticexpialidocious
super<span xml:lang="foo">cali</span>fragilisticexpialidocious
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that -moz-hyphens:none prevents break at &shy; -->
<body xml:lang="en-us">
<div style="width: 5em; -moz-hyphens: none;">
su&#173;per&#173;cal&#173;ifrag&#173;ilis&#173;tic&#173;ex&#173;pi&#173;ali&#173;do&#173;cious
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that hyphenation is not applied to unknown language -->
<body xml:lang="x-unknown-language">
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
div {
margin: 10px;
width: 10px;
font-family: monospace;
-moz-hyphens: auto;
}
</style>
</head>
<!-- test some hyphenations that involve overlapping patterns -->
<body xml:lang="en-us">
<div>
photo
</div>
<div>
photograph
</div>
<div>
photographer
</div>
<div>
photographical
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- style changes don't break hyphenation -->
<body xml:lang="en-us">
<div style="width: 0; -moz-hyphens: auto;">
hy<span style="color:red">phen</span>ation
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- style changes don't break hyphenation -->
<body xml:lang="en-us">
<div style="width: 0; -moz-hyphens: auto;">
h<span style="color:red">yphena</span>tion
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that hyphenation is not applied when language is not specified -->
<body>
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hyphenation test</title></head>
<!-- check that hyphenation is not applied when language is not specified -->
<body>
<div style="width: 5em; -moz-hyphens: auto;">
supercalifragilisticexpialidocious
</div>
</body>
</html>

View File

@ -219,6 +219,26 @@ pref(gfx.font_rendering.graphite.enabled,true) HTTP(..) == glyph-decomposition-g
== auto-hyphenation-8.html auto-hyphenation-8-ref.html
== auto-hyphenation-9.html auto-hyphenation-9-ref.html
== auto-hyphenation-10.html auto-hyphenation-10-ref.html
== auto-hyphenation-xmllang-1.xhtml auto-hyphenation-1-ref.html
!= auto-hyphenation-xmllang-1.xhtml auto-hyphenation-1-notref.html
== auto-hyphenation-xmllang-1a.xhtml auto-hyphenation-1-ref.html
== auto-hyphenation-xmllang-2.xhtml auto-hyphenation-2-ref.html
== auto-hyphenation-xmllang-3.xhtml auto-hyphenation-3-ref.html
== auto-hyphenation-xmllang-4.xhtml auto-hyphenation-4-ref.html
== auto-hyphenation-xmllang-5.xhtml auto-hyphenation-5-ref.html
== auto-hyphenation-xmllang-6.xhtml auto-hyphenation-6-ref.html
== auto-hyphenation-xmllang-7.xhtml auto-hyphenation-7-ref.html
== auto-hyphenation-xmllang-8.xhtml auto-hyphenation-8-ref.html
== auto-hyphenation-xmllang-9.xhtml auto-hyphenation-9-ref.html
== auto-hyphenation-xmllang-10.xhtml auto-hyphenation-10-ref.html
== auto-hyphenation-xmllang-11a.xhtml auto-hyphenation-1-ref.html
== auto-hyphenation-xmllang-11b.xhtml auto-hyphenation-1-ref.html
== auto-hyphenation-xmllang-12a.xhtml auto-hyphenation-4-ref.html
== auto-hyphenation-xmllang-12b.xhtml auto-hyphenation-4-ref.html
== auto-hyphenation-xmllang-13a.xhtml auto-hyphenation-1-ref.html
== auto-hyphenation-xmllang-13b.xhtml auto-hyphenation-1-ref.html
== auto-hyphenation-xmllang-14a.xhtml auto-hyphenation-4-ref.html
== auto-hyphenation-xmllang-14b.xhtml auto-hyphenation-4-ref.html
== auto-hyphenation-af-1.html auto-hyphenation-af-1-ref.html
== auto-hyphenation-bg-1.html auto-hyphenation-bg-1-ref.html
== auto-hyphenation-ca-1.html auto-hyphenation-ca-1-ref.html

View File

@ -32,7 +32,9 @@
#include "nsCSSRuleProcessor.h"
#include "mozilla/dom/Element.h"
#include "nsCSSFrameConstructor.h"
#include "nsHashKeys.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::HTMLColorRule, nsIStyleRule)
@ -94,6 +96,31 @@ nsHTMLStyleSheet::TableQuirkColorRule::MapRuleInfoInto(nsRuleData* aRuleData)
}
}
NS_IMPL_ISUPPORTS1(nsHTMLStyleSheet::LangRule, nsIStyleRule)
/* virtual */ void
nsHTMLStyleSheet::LangRule::MapRuleInfoInto(nsRuleData* aRuleData)
{
if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
nsCSSValue* lang = aRuleData->ValueForLang();
if (lang->GetUnit() == eCSSUnit_Null) {
lang->SetStringValue(mLang, eCSSUnit_Ident);
}
}
}
#ifdef DEBUG
/* virtual */ void
nsHTMLStyleSheet::LangRule::List(FILE* out, int32_t aIndent) const
{
for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
fputs("[lang rule] { language: \"", out);
fputs(NS_ConvertUTF16toUTF8(mLang).get(), out);
fputs("\" }\n", out);
}
#endif
// -----------------------------------------------------------
struct MappedAttrTableEntry : public PLDHashEntryHdr {
@ -138,7 +165,64 @@ static PLDHashTableOps MappedAttrTable_Ops = {
PL_DHashMoveEntryStub,
MappedAttrTable_ClearEntry,
PL_DHashFinalizeStub,
NULL
nullptr
};
// -----------------------------------------------------------
struct LangRuleTableEntry : public PLDHashEntryHdr {
nsRefPtr<nsHTMLStyleSheet::LangRule> mRule;
};
static PLDHashNumber
LangRuleTable_HashKey(PLDHashTable *table, const void *key)
{
const nsString *lang = static_cast<const nsString*>(key);
return HashString(*lang);
}
static void
LangRuleTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
{
LangRuleTableEntry *entry = static_cast<LangRuleTableEntry*>(hdr);
entry->~LangRuleTableEntry();
memset(entry, 0, sizeof(LangRuleTableEntry));
}
static bool
LangRuleTable_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
const void *key)
{
const nsString *lang = static_cast<const nsString*>(key);
const LangRuleTableEntry *entry = static_cast<const LangRuleTableEntry*>(hdr);
return entry->mRule->mLang == *lang;
}
static bool
LangRuleTable_InitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
const void *key)
{
const nsString *lang = static_cast<const nsString*>(key);
LangRuleTableEntry *entry = new (hdr) LangRuleTableEntry();
// Create the unique rule for this language
entry->mRule = new nsHTMLStyleSheet::LangRule(*lang);
return true;
}
static PLDHashTableOps LangRuleTable_Ops = {
PL_DHashAllocTable,
PL_DHashFreeTable,
LangRuleTable_HashKey,
LangRuleTable_MatchEntry,
PL_DHashMoveEntryStub,
LangRuleTable_ClearEntry,
PL_DHashFinalizeStub,
LangRuleTable_InitEntry
};
// -----------------------------------------------------------
@ -152,10 +236,13 @@ nsHTMLStyleSheet::nsHTMLStyleSheet(nsIURI* aURL, nsIDocument* aDocument)
MOZ_ASSERT(aURL);
MOZ_ASSERT(aDocument);
mMappedAttrTable.ops = nullptr;
mLangRuleTable.ops = nullptr;
}
nsHTMLStyleSheet::~nsHTMLStyleSheet()
{
if (mLangRuleTable.ops)
PL_DHashTableFinish(&mLangRuleTable);
if (mMappedAttrTable.ops)
PL_DHashTableFinish(&mMappedAttrTable);
}
@ -212,6 +299,14 @@ nsHTMLStyleSheet::RulesMatching(ElementRuleProcessorData* aData)
if (!ruleWalker->AuthorStyleDisabled() || aData->mElement->IsSVG()) {
aData->mElement->WalkContentStyleRules(ruleWalker);
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#language
// says that the xml:lang attribute overrides HTML's lang attribute,
// so we need to do this after WalkContentStyleRules.
nsString lang;
if (aData->mElement->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang, lang)) {
ruleWalker->Forward(LangRuleFor(lang));
}
}
// Test if style is dependent on content state
@ -387,6 +482,10 @@ nsHTMLStyleSheet::Reset(nsIURI* aURL)
mVisitedRule = nullptr;
mActiveRule = nullptr;
if (mLangRuleTable.ops) {
PL_DHashTableFinish(&mLangRuleTable);
mLangRuleTable.ops = nullptr;
}
if (mMappedAttrTable.ops) {
PL_DHashTableFinish(&mMappedAttrTable);
mMappedAttrTable.ops = nullptr;
@ -474,6 +573,27 @@ nsHTMLStyleSheet::DropMappedAttributes(nsMappedAttributes* aMapped)
NS_ASSERTION(entryCount == mMappedAttrTable.entryCount, "not removed");
}
nsIStyleRule*
nsHTMLStyleSheet::LangRuleFor(const nsString& aLanguage)
{
if (!mLangRuleTable.ops) {
bool res = PL_DHashTableInit(&mLangRuleTable, &LangRuleTable_Ops,
nullptr, sizeof(LangRuleTableEntry), 16);
if (!res) {
NS_ASSERTION(false, "out of memory");
mLangRuleTable.ops = nullptr;
return nullptr;
}
}
LangRuleTableEntry *entry = static_cast<LangRuleTableEntry*>
(PL_DHashTableOperate(&mLangRuleTable, &aLanguage, PL_DHASH_ADD));
if (!entry) {
NS_ASSERTION(false, "out of memory");
return nullptr;
}
return entry->mRule;
}
#ifdef DEBUG
/* virtual */ void
nsHTMLStyleSheet::List(FILE* out, int32_t aIndent) const
@ -522,6 +642,7 @@ nsHTMLStyleSheet::DOMSizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
// - mActiveRule
// - mTableQuirkColorRule
// - mTableTHRule
// - mLangRuleTable
//
// The following members are not measured:
// - mDocument, because it's non-owning

View File

@ -20,6 +20,7 @@
#include "nsIStyleSheet.h"
#include "pldhash.h"
#include "mozilla/Attributes.h"
#include "nsString.h"
class nsMappedAttributes;
@ -76,6 +77,8 @@ public:
UniqueMappedAttributes(nsMappedAttributes* aMapped);
void DropMappedAttributes(nsMappedAttributes* aMapped);
nsIStyleRule* LangRuleFor(const nsString& aLanguage);
private:
nsHTMLStyleSheet(const nsHTMLStyleSheet& aCopy) MOZ_DELETE;
nsHTMLStyleSheet& operator=(const nsHTMLStyleSheet& aCopy) MOZ_DELETE;
@ -136,6 +139,26 @@ private:
virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE;
};
public: // for mLangRuleTable structures only
// Rule to handle xml:lang attributes, of which we have exactly one
// per language string, maintained in mLangRuleTable.
class LangRule MOZ_FINAL : public nsIStyleRule {
public:
LangRule(const nsSubstring& aLang) : mLang(aLang) {}
NS_DECL_ISUPPORTS
// nsIStyleRule interface
virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE;
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE;
#endif
nsString mLang;
};
private:
nsCOMPtr<nsIURI> mURL;
nsIDocument* mDocument;
nsRefPtr<HTMLColorRule> mLinkRule;
@ -145,6 +168,7 @@ private:
nsRefPtr<TableTHRule> mTableTHRule;
PLDHashTable mMappedAttrTable;
PLDHashTable mLangRuleTable;
};
#endif /* !defined(nsHTMLStyleSheet_h_) */