mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
Bug 1370802: Parse lang attributes as atoms. r=heycam
MozReview-Commit-ID: Cnq3wB7aVB1 --HG-- extra : rebase_source : fa0252b78381bf023ab08bf2d9fd13d4c0ed57a1
This commit is contained in:
parent
cba8cd8660
commit
f6dc661b5b
@ -2657,6 +2657,11 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::lang) {
|
||||
aResult.ParseAtom(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
|
||||
"The class attribute should be preparsed and therefore should "
|
||||
|
@ -348,6 +348,33 @@ nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsIContent::GetLang() const
|
||||
{
|
||||
for (const auto* content = this; content; content = content->GetParent()) {
|
||||
if (!content->GetAttrCount() || !content->IsElement()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* element = content->AsElement();
|
||||
|
||||
// xml:lang has precedence over lang on HTML elements (see
|
||||
// XHTML1 section C.7).
|
||||
const nsAttrValue* attr =
|
||||
element->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
|
||||
if (!attr && element->SupportsLangAttr()) {
|
||||
attr = element->GetParsedAttr(nsGkAtoms::lang);
|
||||
}
|
||||
if (attr) {
|
||||
MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
|
||||
MOZ_ASSERT(attr->GetAtomValue());
|
||||
return attr->GetAtomValue();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsIContent::GetBaseURI(bool aTryUseXHRDocBaseURI) const
|
||||
{
|
||||
|
@ -928,26 +928,18 @@ public:
|
||||
/**
|
||||
* Determining language. Look at the nearest ancestor element that has a lang
|
||||
* attribute in the XML namespace or is an HTML/SVG element and has a lang in
|
||||
* no namespace attribute. Returns false if no language was specified.
|
||||
* no namespace attribute.
|
||||
*
|
||||
* Returns null if no language was specified. Can return the empty atom.
|
||||
*/
|
||||
nsIAtom* GetLang() const;
|
||||
|
||||
bool GetLang(nsAString& aResult) const {
|
||||
for (const nsIContent* content = this; content; content = content->GetParent()) {
|
||||
if (content->GetAttrCount() > 0) {
|
||||
// xml:lang has precedence over lang on HTML elements (see
|
||||
// XHTML1 section C.7).
|
||||
bool hasAttr = content->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang,
|
||||
aResult);
|
||||
if (!hasAttr && content->SupportsLangAttr()) {
|
||||
hasAttr = content->GetAttr(kNameSpaceID_None, nsGkAtoms::lang,
|
||||
aResult);
|
||||
}
|
||||
NS_ASSERTION(hasAttr || aResult.IsEmpty(),
|
||||
"GetAttr that returns false should not make string non-empty");
|
||||
if (hasAttr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (auto* lang = GetLang()) {
|
||||
aResult.Assign(nsDependentAtomString(lang));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1219,17 +1219,28 @@ MapLangAttributeInto(const nsMappedAttributes* aAttributes, GenericSpecifiedValu
|
||||
}
|
||||
|
||||
const nsAttrValue* langValue = aAttributes->GetAttr(nsGkAtoms::lang);
|
||||
if (!langValue || langValue->Type() != nsAttrValue::eString) {
|
||||
if (!langValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(langValue->Type() == nsAttrValue::eAtom);
|
||||
if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font))) {
|
||||
aData->SetIdentStringValueIfUnset(eCSSProperty__x_lang,
|
||||
langValue->GetStringValue());
|
||||
nsIAtom* atom = langValue->GetAtomValue();
|
||||
|
||||
const nsDependentAtomString atomString(atom);
|
||||
Maybe<nsCOMPtr<nsIAtom>> lowerAtom;
|
||||
if (nsContentUtils::StringContainsASCIIUpper(atomString)) {
|
||||
nsAutoString dest;
|
||||
dest.SetCapacity(atomString.Length());
|
||||
nsContentUtils::ASCIIToLower(atomString, dest);
|
||||
lowerAtom.emplace(NS_AtomizeMainThread(dest));
|
||||
}
|
||||
|
||||
aData->SetIdentAtomValueIfUnset(
|
||||
eCSSProperty__x_lang, lowerAtom ? lowerAtom->get() : atom);
|
||||
}
|
||||
if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))) {
|
||||
if (!aData->PropertyIsSet(eCSSProperty_text_emphasis_position)) {
|
||||
const nsAString& lang = langValue->GetStringValue();
|
||||
const nsIAtom* lang = langValue->GetAtomValue();
|
||||
if (nsStyleUtil::MatchesLanguagePrefix(lang, u"zh")) {
|
||||
aData->SetKeywordValue(eCSSProperty_text_emphasis_position,
|
||||
NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH);
|
||||
|
@ -53,6 +53,9 @@ public:
|
||||
inline void SetIdentStringValue(nsCSSPropertyID aId, const nsString& aValue);
|
||||
inline void SetIdentStringValueIfUnset(nsCSSPropertyID aId, const nsString& aValue);
|
||||
|
||||
inline void SetIdentAtomValue(nsCSSPropertyID aId, nsIAtom* aValue);
|
||||
inline void SetIdentAtomValueIfUnset(nsCSSPropertyID aId, nsIAtom* aValue);
|
||||
|
||||
// Set a property to a keyword (usually NS_STYLE_* or StyleFoo::*)
|
||||
inline void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue);
|
||||
inline void SetKeywordValueIfUnset(nsCSSPropertyID aId, int32_t aValue);
|
||||
|
@ -40,6 +40,18 @@ GenericSpecifiedValues::SetIdentStringValueIfUnset(nsCSSPropertyID aId, const ns
|
||||
MOZ_STYLO_FORWARD(SetIdentStringValueIfUnset, (aId, aValue))
|
||||
}
|
||||
|
||||
void
|
||||
GenericSpecifiedValues::SetIdentAtomValueIfUnset(nsCSSPropertyID aId, nsIAtom* aValue)
|
||||
{
|
||||
MOZ_STYLO_FORWARD(SetIdentAtomValueIfUnset, (aId, aValue))
|
||||
}
|
||||
|
||||
void
|
||||
GenericSpecifiedValues::SetIdentAtomValue(nsCSSPropertyID aId, nsIAtom* aValue)
|
||||
{
|
||||
MOZ_STYLO_FORWARD(SetIdentAtomValue, (aId, aValue))
|
||||
}
|
||||
|
||||
void
|
||||
GenericSpecifiedValues::SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
|
||||
{
|
||||
|
@ -821,24 +821,24 @@ Gecko_MatchLang(RawGeckoElementBorrowed aElement,
|
||||
aValue, aElement->OwnerDoc());
|
||||
}
|
||||
|
||||
if (aOverrideLang) {
|
||||
nsDependentAtomString overrideLang(aOverrideLang);
|
||||
return nsCSSRuleProcessor::LangPseudoMatches(aElement, &overrideLang, true,
|
||||
aValue, aElement->OwnerDoc());
|
||||
}
|
||||
|
||||
return nsCSSRuleProcessor::LangPseudoMatches(aElement, nullptr, true,
|
||||
return nsCSSRuleProcessor::LangPseudoMatches(aElement, aOverrideLang, true,
|
||||
aValue, aElement->OwnerDoc());
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
Gecko_GetXMLLangValue(RawGeckoElementBorrowed aElement)
|
||||
{
|
||||
nsString string;
|
||||
if (aElement->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang, string)) {
|
||||
return NS_Atomize(string).take();
|
||||
const nsAttrValue* attr =
|
||||
aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
|
||||
|
||||
if (!attr) {
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
|
||||
|
||||
nsCOMPtr<nsIAtom> atom = attr->GetAtomValue();
|
||||
return atom.forget().take();
|
||||
}
|
||||
|
||||
template <typename Implementor>
|
||||
@ -853,6 +853,7 @@ template <typename Implementor>
|
||||
static nsIAtom*
|
||||
LangValue(Implementor* aElement)
|
||||
{
|
||||
// TODO(emilio): Deduplicate a bit with nsIContent::GetLang().
|
||||
const nsAttrValue* attr =
|
||||
aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
|
||||
if (!attr && aElement->SupportsLangAttr()) {
|
||||
@ -863,9 +864,9 @@ LangValue(Implementor* aElement)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsString lang;
|
||||
attr->ToString(lang);
|
||||
return NS_Atomize(lang).take();
|
||||
MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
|
||||
nsCOMPtr<nsIAtom> atom = attr->GetAtomValue();
|
||||
return atom.forget().take();
|
||||
}
|
||||
|
||||
template <typename Implementor, typename MatchFn>
|
||||
|
@ -47,11 +47,17 @@ ServoSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
|
||||
const nsString& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom = NS_Atomize(aValue);
|
||||
Servo_DeclarationBlock_SetIdentStringValue(mDecl, aId, atom);
|
||||
SetIdentAtomValue(aId, atom);
|
||||
}
|
||||
|
||||
void
|
||||
ServoSpecifiedValues::SetIdentAtomValue(nsCSSPropertyID aId, nsIAtom* aValue)
|
||||
{
|
||||
Servo_DeclarationBlock_SetIdentStringValue(mDecl, aId, aValue);
|
||||
if (aId == eCSSProperty__x_lang) {
|
||||
// This forces the lang prefs result to be cached
|
||||
// so that we can access them off main thread during traversal
|
||||
mPresContext->ForceCacheLang(atom);
|
||||
mPresContext->ForceCacheLang(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,4 +135,4 @@ ServoSpecifiedValues::SetBackgroundImage(nsAttrValue& aValue)
|
||||
aValue.ToString(str);
|
||||
Servo_DeclarationBlock_SetBackgroundImage(mDecl, str,
|
||||
mPresContext->Document()->DefaultStyleAttrURLData());
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SetIdentAtomValue(nsCSSPropertyID aId, nsIAtom* aValue);
|
||||
|
||||
void SetIdentAtomValueIfUnset(nsCSSPropertyID aId, nsIAtom* aValue)
|
||||
{
|
||||
if (!PropertyIsSet(aId)) {
|
||||
SetIdentAtomValue(aId, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue);
|
||||
|
||||
void SetKeywordValueIfUnset(nsCSSPropertyID aId, int32_t aValue)
|
||||
|
@ -1678,7 +1678,7 @@ IsSignificantChildMaybeThreadSafe(const nsIContent* aContent,
|
||||
|
||||
/* static */ bool
|
||||
nsCSSRuleProcessor::LangPseudoMatches(const mozilla::dom::Element* aElement,
|
||||
const nsAString* aOverrideLang,
|
||||
const nsIAtom* aOverrideLang,
|
||||
bool aHasOverrideLang,
|
||||
const char16_t* aString,
|
||||
const nsIDocument* aDocument)
|
||||
@ -1692,52 +1692,42 @@ nsCSSRuleProcessor::LangPseudoMatches(const mozilla::dom::Element* aElement,
|
||||
// this is currently no property and since the language is inherited
|
||||
// from the parent we have to be prepared to look at all parent
|
||||
// nodes. The language itself is encoded in the LANG attribute.
|
||||
bool haveLanguage = false;
|
||||
nsAutoString language;
|
||||
if (aHasOverrideLang) {
|
||||
if (aOverrideLang) {
|
||||
language = *aOverrideLang;
|
||||
haveLanguage = true;
|
||||
}
|
||||
} else {
|
||||
haveLanguage = aElement->GetLang(language);
|
||||
}
|
||||
|
||||
if (haveLanguage) {
|
||||
return nsStyleUtil::DashMatchCompare(language,
|
||||
if (auto* language = aHasOverrideLang ? aOverrideLang : aElement->GetLang()) {
|
||||
return nsStyleUtil::DashMatchCompare(nsDependentAtomString(language),
|
||||
nsDependentString(aString),
|
||||
nsASCIICaseInsensitiveStringComparator());
|
||||
}
|
||||
|
||||
if (aDocument) {
|
||||
// Try to get the language from the HTTP header or if this
|
||||
// is missing as well from the preferences.
|
||||
// The content language can be a comma-separated list of
|
||||
// language codes.
|
||||
aDocument->GetContentLanguage(language);
|
||||
|
||||
nsDependentString langString(aString);
|
||||
language.StripWhitespace();
|
||||
int32_t begin = 0;
|
||||
int32_t len = language.Length();
|
||||
while (begin < len) {
|
||||
int32_t end = language.FindChar(char16_t(','), begin);
|
||||
if (end == kNotFound) {
|
||||
end = len;
|
||||
}
|
||||
if (nsStyleUtil::DashMatchCompare(Substring(language, begin,
|
||||
end-begin),
|
||||
langString,
|
||||
nsASCIICaseInsensitiveStringComparator())) {
|
||||
return true;
|
||||
}
|
||||
begin = end + 1;
|
||||
}
|
||||
if (begin < len) {
|
||||
return true;
|
||||
}
|
||||
if (!aDocument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to get the language from the HTTP header or if this
|
||||
// is missing as well from the preferences.
|
||||
// The content language can be a comma-separated list of
|
||||
// language codes.
|
||||
nsAutoString language;
|
||||
aDocument->GetContentLanguage(language);
|
||||
|
||||
nsDependentString langString(aString);
|
||||
language.StripWhitespace();
|
||||
int32_t begin = 0;
|
||||
int32_t len = language.Length();
|
||||
while (begin < len) {
|
||||
int32_t end = language.FindChar(char16_t(','), begin);
|
||||
if (end == kNotFound) {
|
||||
end = len;
|
||||
}
|
||||
if (nsStyleUtil::DashMatchCompare(Substring(language, begin, end - begin),
|
||||
langString,
|
||||
nsASCIICaseInsensitiveStringComparator())) {
|
||||
return true;
|
||||
}
|
||||
begin = end + 1;
|
||||
}
|
||||
if (begin < len) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ public:
|
||||
bool* const aDependence = nullptr);
|
||||
|
||||
static bool LangPseudoMatches(const mozilla::dom::Element* aElement,
|
||||
const nsAString* aOverrideLang,
|
||||
const nsIAtom* aOverrideLang,
|
||||
bool aHasOverrideLang,
|
||||
const char16_t* aString,
|
||||
const nsIDocument* aDocument);
|
||||
|
@ -136,6 +136,19 @@ struct nsRuleData final: mozilla::GenericSpecifiedValues
|
||||
}
|
||||
}
|
||||
|
||||
void SetIdentAtomValue(nsCSSPropertyID aId, nsIAtom* aValue)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atom = aValue;
|
||||
ValueFor(aId)->SetAtomIdentValue(atom.forget());
|
||||
}
|
||||
|
||||
void SetIdentAtomValueIfUnset(nsCSSPropertyID aId, nsIAtom* aValue)
|
||||
{
|
||||
if (!PropertyIsSet(aId)) {
|
||||
SetIdentAtomValue(aId, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
void SetKeywordValue(nsCSSPropertyID aId, int32_t aValue)
|
||||
{
|
||||
ValueFor(aId)->SetIntValue(aValue, eCSSUnit_Enumerated);
|
||||
|
@ -3606,12 +3606,11 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, GeckoStyleContext* aContext,
|
||||
// -x-lang: string, inherit
|
||||
// This is not a real CSS property, it is an HTML attribute mapped to CSS.
|
||||
const nsCSSValue* langValue = aRuleData->ValueForLang();
|
||||
if (eCSSUnit_Ident == langValue->GetUnit()) {
|
||||
nsAutoString lang;
|
||||
langValue->GetStringValue(lang);
|
||||
if (eCSSUnit_AtomIdent == langValue->GetUnit()) {
|
||||
MOZ_ASSERT(!nsContentUtils::StringContainsASCIIUpper(
|
||||
nsDependentAtomString(langValue->GetAtomValue())));
|
||||
|
||||
nsContentUtils::ASCIIToLower(lang);
|
||||
aFont->mLanguage = NS_Atomize(lang);
|
||||
aFont->mLanguage = langValue->GetAtomValue();
|
||||
aFont->mExplicitLanguage = true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user