Bug 216563 - implement <svg:switch>.

Patch by scootermorris@comcast.net, r=afri, sr=dbaron
This commit is contained in:
tor%cs.brown.edu 2004-08-23 21:10:39 +00:00
parent 1466e099f5
commit 0c326e84e7
14 changed files with 512 additions and 68 deletions

View File

@ -101,6 +101,10 @@
#include "nsIDOMXPathEvaluator.h"
#include "nsNodeInfoManager.h"
#ifdef MOZ_SVG
PRBool NS_SVG_TestFeature(const nsAString &fstr);
#endif /* MOZ_SVG */
#ifdef DEBUG_waterson
/**
@ -1183,6 +1187,17 @@ nsGenericElement::InternalIsSupported(const nsAString& aFeature,
*aReturn = gHaveXPathDOM;
}
#ifdef MOZ_SVG
// Check for SVG Features
else if (NS_SVG_TestFeature(aFeature)) {
// Should we test the version also? The SVG Test
// Suite (struct-dom-02-b.svg) uses version 2.0 in the
// domImpl.hasFeature call. This makes no sense to me,
// so I'm going to skip testing the version here for now....
*aReturn = PR_TRUE;
}
#endif /* MOZ_SVG */
return NS_OK;
}

View File

@ -72,6 +72,9 @@ public:
static PRBool IsHTMLLink(nsIContent *aContent, nsIAtom *aTag, nsPresContext *aPresContext, nsLinkState *aState);
static PRBool IsSimpleXlink(nsIContent *aContent, nsPresContext *aPresContext, nsLinkState *aState);
static PRBool DashMatchCompare(const nsAString& aAttributeValue,
const nsAString& aSelectorValue,
const nsStringComparator& aComparator);
};

View File

@ -3026,34 +3026,6 @@ static PRBool IsSignificantChild(nsIContent* aChild, PRBool aAcceptNonWhitespace
return PR_FALSE;
}
static PRBool
DashMatchCompare(const nsAString& aAttributeValue,
const nsAString& aSelectorValue,
const nsStringComparator& aComparator)
{
PRBool result;
PRUint32 selectorLen = aSelectorValue.Length();
PRUint32 attributeLen = aAttributeValue.Length();
if (selectorLen > attributeLen) {
result = PR_FALSE;
}
else {
nsAString::const_iterator iter;
if (selectorLen != attributeLen &&
*aAttributeValue.BeginReading(iter).advance(selectorLen) !=
PRUnichar('-')) {
// to match, the aAttributeValue must have a dash after the end of
// the aSelectorValue's text (unless the aSelectorValue and the
// aAttributeValue have the same text)
result = PR_FALSE;
}
else {
result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
}
}
return result;
}
// This function is to be called once we have fetched a value for an attribute
// whose namespace and name match those of aAttrSelector. This function
// performs comparisons on the value only, based on aAttrSelector->mFunction.
@ -3072,7 +3044,7 @@ static PRBool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
case NS_ATTR_FUNC_INCLUDES:
return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
case NS_ATTR_FUNC_DASHMATCH:
return DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
case NS_ATTR_FUNC_ENDSMATCH:
return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
case NS_ATTR_FUNC_BEGINSMATCH:
@ -3219,8 +3191,8 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// nodes. The language itself is encoded in the LANG attribute.
const nsString* lang = data.GetLang();
if (lang && !lang->IsEmpty()) { // null check for out-of-memory
result = localTrue == DashMatchCompare(*lang,
nsDependentString(pseudoClass->mString),
result = localTrue == nsStyleUtil::DashMatchCompare(*lang,
nsDependentString(pseudoClass->mString),
nsCaseInsensitiveStringComparator());
}
else {
@ -3242,7 +3214,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
if (end == kNotFound) {
end = len;
}
if (DashMatchCompare(Substring(language, begin, end-begin),
if (nsStyleUtil::DashMatchCompare(Substring(language, begin, end-begin),
langString,
nsCaseInsensitiveStringComparator())) {
result = localTrue;

View File

@ -501,3 +501,31 @@ PRBool nsStyleUtil::IsSimpleXlink(nsIContent *aContent, nsPresContext *aPresCont
}
return rv;
}
// Compare two language strings
PRBool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue,
const nsAString& aSelectorValue,
const nsStringComparator& aComparator)
{
PRBool result;
PRUint32 selectorLen = aSelectorValue.Length();
PRUint32 attributeLen = aAttributeValue.Length();
if (selectorLen > attributeLen) {
result = PR_FALSE;
}
else {
nsAString::const_iterator iter;
if (selectorLen != attributeLen &&
*aAttributeValue.BeginReading(iter).advance(selectorLen) !=
PRUnichar('-')) {
// to match, the aAttributeValue must have a dash after the end of
// the aSelectorValue's text (unless the aSelectorValue and the
// aAttributeValue have the same text)
result = PR_FALSE;
}
else {
result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
}
}
return result;
}

View File

@ -69,6 +69,7 @@ SVG_ATOM(polyline, "polyline")
SVG_ATOM(rect, "rect")
SVG_ATOM(script, "script")
SVG_ATOM(svg, "svg")
SVG_ATOM(svgSwitch, "switch") // switch is a C++ keyword, hence svgSwitch
SVG_ATOM(text, "text")
SVG_ATOM(tref, "tref")
SVG_ATOM(tspan, "tspan")
@ -121,6 +122,8 @@ SVG_ATOM(pointer_events, "pointer-events")
SVG_ATOM(points, "points")
SVG_ATOM(preserveAspectRatio, "preserveAspectRatio")
SVG_ATOM(r, "r")
SVG_ATOM(requiredExtensions, "requiredExtensions")
SVG_ATOM(requiredFeatures, "requiredFeatures")
SVG_ATOM(rx, "rx")
SVG_ATOM(ry, "ry")
SVG_ATOM(shape_rendering, "shape-rendering")
@ -134,6 +137,7 @@ SVG_ATOM(stroke_miterlimit, "stroke-miterlimit")
SVG_ATOM(stroke_opacity, "stroke-opacity")
SVG_ATOM(stroke_width, "stroke-width")
SVG_ATOM(style, "style")
SVG_ATOM(systemLanguage, "systemLanguage")
SVG_ATOM(text_anchor, "text-anchor")
SVG_ATOM(text_decoration, "text-decoration")
SVG_ATOM(text_rendering, "text-rendering")

View File

@ -69,6 +69,7 @@ SVG_ATOM(polyline, "polyline")
SVG_ATOM(rect, "rect")
SVG_ATOM(script, "script")
SVG_ATOM(svg, "svg")
SVG_ATOM(svgSwitch, "switch") // switch is a C++ keyword, hence svgSwitch
SVG_ATOM(text, "text")
SVG_ATOM(tref, "tref")
SVG_ATOM(tspan, "tspan")
@ -121,6 +122,8 @@ SVG_ATOM(pointer_events, "pointer-events")
SVG_ATOM(points, "points")
SVG_ATOM(preserveAspectRatio, "preserveAspectRatio")
SVG_ATOM(r, "r")
SVG_ATOM(requiredExtensions, "requiredExtensions")
SVG_ATOM(requiredFeatures, "requiredFeatures")
SVG_ATOM(rx, "rx")
SVG_ATOM(ry, "ry")
SVG_ATOM(shape_rendering, "shape-rendering")
@ -134,6 +137,7 @@ SVG_ATOM(stroke_miterlimit, "stroke-miterlimit")
SVG_ATOM(stroke_opacity, "stroke-opacity")
SVG_ATOM(stroke_width, "stroke-width")
SVG_ATOM(style, "style")
SVG_ATOM(systemLanguage, "systemLanguage")
SVG_ATOM(text_anchor, "text-anchor")
SVG_ATOM(text_decoration, "text-decoration")
SVG_ATOM(text_rendering, "text-rendering")

View File

@ -150,6 +150,7 @@ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
#include "nsSVGAtoms.h"
#include "nsISVGTextContainerFrame.h"
#include "nsISVGContainerFrame.h"
#include "nsStyleUtil.h"
nsresult
NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
@ -183,6 +184,8 @@ nsresult
NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* parent, nsIFrame** aNewFrame);
nsresult
NS_NewSVGDefsFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
PRBool
NS_SVG_TestFeatures (const nsAString& value);
#endif
#include "nsIDocument.h"
@ -365,6 +368,47 @@ static PRInt32 FFWC_nextInFlows=0;
static PRInt32 FFWC_slowSearchForText=0;
#endif
#ifdef MOZ_SVG
// Test to see if this language is supported
static PRBool
SVG_TestLanguage(const nsSubstring& lstr, const nsSubstring& prefs)
{
// Compare list to attribute value, which may be a list
// According to the SVG 1.1 Spec (at least as I read it), we should take
// the first attribute value and check it for any matches in the users
// preferences, including any prefix matches.
// This algorithm is O(M*N)
PRInt32 vbegin = 0;
PRInt32 vlen = lstr.Length();
while (vbegin < vlen) {
PRInt32 vend = lstr.FindChar(PRUnichar(','), vbegin);
if (vend == kNotFound) {
vend = vlen;
}
PRInt32 gbegin = 0;
PRInt32 glen = prefs.Length();
while (gbegin < glen) {
PRInt32 gend = prefs.FindChar(PRUnichar(','), gbegin);
if (gend == kNotFound) {
gend = glen;
}
const nsDefaultStringComparator defaultComparator;
const nsStringComparator& comparator =
NS_STATIC_CAST(const nsStringComparator&, defaultComparator);
if (nsStyleUtil::DashMatchCompare(Substring(lstr, vbegin, vend-vbegin),
Substring(prefs, gbegin, gend-gbegin),
comparator)) {
return PR_TRUE;
}
gbegin = gend + 1;
}
vbegin = vend + 1;
}
return PR_FALSE;
}
#endif
//----------------------------------------------------------------------
//
// When inline frames get weird and have block frames in them, we
@ -6859,6 +6903,152 @@ nsCSSFrameConstructor::ConstructMathMLFrame(nsIPresShell* aPresShell,
// SVG
#ifdef MOZ_SVG
nsresult
nsCSSFrameConstructor::TestSVGConditions(nsIContent* aContent,
PRBool& aHasRequiredExtensions,
PRBool& aHasRequiredFeatures,
PRBool& aHasSystemLanguage)
{
nsresult rv = NS_OK;
nsAutoString value;
// Only elements can have tests on them
if (! aContent->IsContentOfType(nsIContent::eELEMENT)) {
aHasRequiredExtensions = PR_FALSE;
aHasRequiredFeatures = PR_FALSE;
aHasSystemLanguage = PR_FALSE;
return rv;
}
// Required Extensions
//
// The requiredExtensions attribute defines a list of required language
// extensions. Language extensions are capabilities within a user agent that
// go beyond the feature set defined in the SVG specification.
// Each extension is identified by a URI reference.
rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::requiredExtensions, value);
if (NS_FAILED(rv))
return rv;
aHasRequiredExtensions = PR_TRUE;
if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
// For now, claim that mozilla's SVG implementation supports
// no extensions. So, if extensions are required, we don't have
// them available.
aHasRequiredExtensions = PR_FALSE;
}
// Required Features
aHasRequiredFeatures = PR_TRUE;
rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::requiredFeatures, value);
if (NS_FAILED(rv))
return rv;
if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
aHasRequiredFeatures = NS_SVG_TestFeatures(value);
}
// systemLanguage
//
// Evaluates to "true" if one of the languages indicated by user preferences
// exactly equals one of the languages given in the value of this parameter,
// or if one of the languages indicated by user preferences exactly equals a
// prefix of one of the languages given in the value of this parameter such
// that the first tag character following the prefix is "-".
aHasSystemLanguage = PR_TRUE;
rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::systemLanguage, value);
if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
// Get our language preferences
nsAutoString langPrefs(nsContentUtils::GetLocalizedStringPref("intl.accept_languages"));
if (!langPrefs.IsEmpty()) {
langPrefs.StripWhitespace();
value.StripWhitespace();
#ifdef DEBUG_scooter
printf("Calling SVG_TestLanguage('%s','%s')\n", NS_ConvertUCS2toUTF8(value).get(),
NS_ConvertUCS2toUTF8(langPrefs).get());
#endif
aHasSystemLanguage = SVG_TestLanguage(value, langPrefs);
} else {
// For now, evaluate to true.
NS_WARNING("no default language specified for systemLanguage conditional test");
aHasSystemLanguage = PR_TRUE;
}
return NS_OK;
}
return rv;
}
nsresult
nsCSSFrameConstructor::SVGSwitchProcessChildren(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aFrame,
nsFrameItems& aFrameItems)
{
nsresult rv = NS_OK;
PRBool isFinished = PR_FALSE;
PRBool hasRequiredExtensions = PR_FALSE;
PRBool hasRequiredFeatures = PR_FALSE;
PRBool hasSystemLanguage = PR_FALSE;
// save the incoming pseudo frame state
nsPseudoFrames priorPseudoFrames;
aState.mPseudoFrames.Reset(&priorPseudoFrames);
// The 'switch' element evaluates the requiredFeatures,
// requiredExtensions and systemLanguage attributes on its direct child
// elements in order, and then processes and renders the first child for
// which these attributes evaluate to true. All others will be bypassed and
// therefore not rendered.
ChildIterator iter, last;
for (ChildIterator::Init(aContent, &iter, &last);
(iter != last) && (! isFinished);
++iter) {
nsCOMPtr<nsIContent> child(*iter);
rv = TestSVGConditions(child,
hasRequiredExtensions,
hasRequiredFeatures,
hasSystemLanguage);
#ifdef DEBUG_scooter
printf("SwitchProcessChildren: Required Extentions = %s, Required Features = %s, System Language = %s\n",
hasRequiredExtensions ? "true" : "false",
hasRequiredFeatures ? "true" : "false",
hasSystemLanguage ? "true" : "false");
#endif
if (NS_FAILED(rv))
return rv;
if (hasRequiredExtensions &&
hasRequiredFeatures &&
hasSystemLanguage) {
rv = ConstructFrame(aPresShell, aPresContext, aState,
nsCOMPtr<nsIContent>(*iter),
aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
if (child->IsContentOfType(nsIContent::eELEMENT)) {
break;
}
}
}
// process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aFrameItems);
}
// restore the incoming pseudo frame state
aState.mPseudoFrames = priorPseudoFrames;
return rv;
}
nsresult
nsCSSFrameConstructor::ConstructSVGFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@ -6989,8 +7179,13 @@ nsCSSFrameConstructor::ConstructSVGFrame(nsIPresShell* aPresShell,
// Process the child content if requested
nsFrameItems childItems;
if (processChildren) {
rv = ProcessChildren(aPresShell, aPresContext, aState, aContent,
newFrame, PR_TRUE, childItems, PR_FALSE);
if (aTag == nsSVGAtoms::svgSwitch) {
rv = SVGSwitchProcessChildren(aPresShell, aPresContext, aState, aContent,
newFrame, childItems);
} else {
rv = ProcessChildren(aPresShell, aPresContext, aState, aContent,
newFrame, PR_TRUE, childItems, PR_FALSE);
}
CreateAnonymousFrames(aPresShell, aPresContext, aTag, aState, aContent, newFrame,
PR_FALSE, childItems);

View File

@ -620,6 +620,18 @@ private:
// SVG - rods
#ifdef MOZ_SVG
nsresult TestSVGConditions(nsIContent* aContent,
PRBool& aHasRequiredExtensions,
PRBool& aHasRequiredFeatures,
PRBool& aHasSystemLanguage);
nsresult SVGSwitchProcessChildren(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aFrame,
nsFrameItems& aFrameItems);
nsresult ConstructSVGFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsFrameConstructorState& aState,

View File

@ -61,6 +61,7 @@ REQUIRES = xpcom \
imglib2 \
js \
xpconnect \
unicharutil \
$(NULL)
CPPSRCS = \

View File

@ -150,6 +150,7 @@ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
#include "nsSVGAtoms.h"
#include "nsISVGTextContainerFrame.h"
#include "nsISVGContainerFrame.h"
#include "nsStyleUtil.h"
nsresult
NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
@ -183,6 +184,8 @@ nsresult
NS_NewSVGTSpanFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame* parent, nsIFrame** aNewFrame);
nsresult
NS_NewSVGDefsFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsIFrame** aNewFrame);
PRBool
NS_SVG_TestFeatures (const nsAString& value);
#endif
#include "nsIDocument.h"
@ -365,6 +368,47 @@ static PRInt32 FFWC_nextInFlows=0;
static PRInt32 FFWC_slowSearchForText=0;
#endif
#ifdef MOZ_SVG
// Test to see if this language is supported
static PRBool
SVG_TestLanguage(const nsSubstring& lstr, const nsSubstring& prefs)
{
// Compare list to attribute value, which may be a list
// According to the SVG 1.1 Spec (at least as I read it), we should take
// the first attribute value and check it for any matches in the users
// preferences, including any prefix matches.
// This algorithm is O(M*N)
PRInt32 vbegin = 0;
PRInt32 vlen = lstr.Length();
while (vbegin < vlen) {
PRInt32 vend = lstr.FindChar(PRUnichar(','), vbegin);
if (vend == kNotFound) {
vend = vlen;
}
PRInt32 gbegin = 0;
PRInt32 glen = prefs.Length();
while (gbegin < glen) {
PRInt32 gend = prefs.FindChar(PRUnichar(','), gbegin);
if (gend == kNotFound) {
gend = glen;
}
const nsDefaultStringComparator defaultComparator;
const nsStringComparator& comparator =
NS_STATIC_CAST(const nsStringComparator&, defaultComparator);
if (nsStyleUtil::DashMatchCompare(Substring(lstr, vbegin, vend-vbegin),
Substring(prefs, gbegin, gend-gbegin),
comparator)) {
return PR_TRUE;
}
gbegin = gend + 1;
}
vbegin = vend + 1;
}
return PR_FALSE;
}
#endif
//----------------------------------------------------------------------
//
// When inline frames get weird and have block frames in them, we
@ -6859,6 +6903,152 @@ nsCSSFrameConstructor::ConstructMathMLFrame(nsIPresShell* aPresShell,
// SVG
#ifdef MOZ_SVG
nsresult
nsCSSFrameConstructor::TestSVGConditions(nsIContent* aContent,
PRBool& aHasRequiredExtensions,
PRBool& aHasRequiredFeatures,
PRBool& aHasSystemLanguage)
{
nsresult rv = NS_OK;
nsAutoString value;
// Only elements can have tests on them
if (! aContent->IsContentOfType(nsIContent::eELEMENT)) {
aHasRequiredExtensions = PR_FALSE;
aHasRequiredFeatures = PR_FALSE;
aHasSystemLanguage = PR_FALSE;
return rv;
}
// Required Extensions
//
// The requiredExtensions attribute defines a list of required language
// extensions. Language extensions are capabilities within a user agent that
// go beyond the feature set defined in the SVG specification.
// Each extension is identified by a URI reference.
rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::requiredExtensions, value);
if (NS_FAILED(rv))
return rv;
aHasRequiredExtensions = PR_TRUE;
if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
// For now, claim that mozilla's SVG implementation supports
// no extensions. So, if extensions are required, we don't have
// them available.
aHasRequiredExtensions = PR_FALSE;
}
// Required Features
aHasRequiredFeatures = PR_TRUE;
rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::requiredFeatures, value);
if (NS_FAILED(rv))
return rv;
if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
aHasRequiredFeatures = NS_SVG_TestFeatures(value);
}
// systemLanguage
//
// Evaluates to "true" if one of the languages indicated by user preferences
// exactly equals one of the languages given in the value of this parameter,
// or if one of the languages indicated by user preferences exactly equals a
// prefix of one of the languages given in the value of this parameter such
// that the first tag character following the prefix is "-".
aHasSystemLanguage = PR_TRUE;
rv = aContent->GetAttr(kNameSpaceID_None, nsSVGAtoms::systemLanguage, value);
if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
// Get our language preferences
nsAutoString langPrefs(nsContentUtils::GetLocalizedStringPref("intl.accept_languages"));
if (!langPrefs.IsEmpty()) {
langPrefs.StripWhitespace();
value.StripWhitespace();
#ifdef DEBUG_scooter
printf("Calling SVG_TestLanguage('%s','%s')\n", NS_ConvertUCS2toUTF8(value).get(),
NS_ConvertUCS2toUTF8(langPrefs).get());
#endif
aHasSystemLanguage = SVG_TestLanguage(value, langPrefs);
} else {
// For now, evaluate to true.
NS_WARNING("no default language specified for systemLanguage conditional test");
aHasSystemLanguage = PR_TRUE;
}
return NS_OK;
}
return rv;
}
nsresult
nsCSSFrameConstructor::SVGSwitchProcessChildren(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aFrame,
nsFrameItems& aFrameItems)
{
nsresult rv = NS_OK;
PRBool isFinished = PR_FALSE;
PRBool hasRequiredExtensions = PR_FALSE;
PRBool hasRequiredFeatures = PR_FALSE;
PRBool hasSystemLanguage = PR_FALSE;
// save the incoming pseudo frame state
nsPseudoFrames priorPseudoFrames;
aState.mPseudoFrames.Reset(&priorPseudoFrames);
// The 'switch' element evaluates the requiredFeatures,
// requiredExtensions and systemLanguage attributes on its direct child
// elements in order, and then processes and renders the first child for
// which these attributes evaluate to true. All others will be bypassed and
// therefore not rendered.
ChildIterator iter, last;
for (ChildIterator::Init(aContent, &iter, &last);
(iter != last) && (! isFinished);
++iter) {
nsCOMPtr<nsIContent> child(*iter);
rv = TestSVGConditions(child,
hasRequiredExtensions,
hasRequiredFeatures,
hasSystemLanguage);
#ifdef DEBUG_scooter
printf("SwitchProcessChildren: Required Extentions = %s, Required Features = %s, System Language = %s\n",
hasRequiredExtensions ? "true" : "false",
hasRequiredFeatures ? "true" : "false",
hasSystemLanguage ? "true" : "false");
#endif
if (NS_FAILED(rv))
return rv;
if (hasRequiredExtensions &&
hasRequiredFeatures &&
hasSystemLanguage) {
rv = ConstructFrame(aPresShell, aPresContext, aState,
nsCOMPtr<nsIContent>(*iter),
aFrame, aFrameItems);
if (NS_FAILED(rv))
return rv;
if (child->IsContentOfType(nsIContent::eELEMENT)) {
break;
}
}
}
// process the current pseudo frame state
if (!aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aFrameItems);
}
// restore the incoming pseudo frame state
aState.mPseudoFrames = priorPseudoFrames;
return rv;
}
nsresult
nsCSSFrameConstructor::ConstructSVGFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@ -6989,8 +7179,13 @@ nsCSSFrameConstructor::ConstructSVGFrame(nsIPresShell* aPresShell,
// Process the child content if requested
nsFrameItems childItems;
if (processChildren) {
rv = ProcessChildren(aPresShell, aPresContext, aState, aContent,
newFrame, PR_TRUE, childItems, PR_FALSE);
if (aTag == nsSVGAtoms::svgSwitch) {
rv = SVGSwitchProcessChildren(aPresShell, aPresContext, aState, aContent,
newFrame, childItems);
} else {
rv = ProcessChildren(aPresShell, aPresContext, aState, aContent,
newFrame, PR_TRUE, childItems, PR_FALSE);
}
CreateAnonymousFrames(aPresShell, aPresContext, aTag, aState, aContent, newFrame,
PR_FALSE, childItems);

View File

@ -620,6 +620,18 @@ private:
// SVG - rods
#ifdef MOZ_SVG
nsresult TestSVGConditions(nsIContent* aContent,
PRBool& aHasRequiredExtensions,
PRBool& aHasRequiredFeatures,
PRBool& aHasSystemLanguage);
nsresult SVGSwitchProcessChildren(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aFrame,
nsFrameItems& aFrameItems);
nsresult ConstructSVGFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsFrameConstructorState& aState,

View File

@ -3026,34 +3026,6 @@ static PRBool IsSignificantChild(nsIContent* aChild, PRBool aAcceptNonWhitespace
return PR_FALSE;
}
static PRBool
DashMatchCompare(const nsAString& aAttributeValue,
const nsAString& aSelectorValue,
const nsStringComparator& aComparator)
{
PRBool result;
PRUint32 selectorLen = aSelectorValue.Length();
PRUint32 attributeLen = aAttributeValue.Length();
if (selectorLen > attributeLen) {
result = PR_FALSE;
}
else {
nsAString::const_iterator iter;
if (selectorLen != attributeLen &&
*aAttributeValue.BeginReading(iter).advance(selectorLen) !=
PRUnichar('-')) {
// to match, the aAttributeValue must have a dash after the end of
// the aSelectorValue's text (unless the aSelectorValue and the
// aAttributeValue have the same text)
result = PR_FALSE;
}
else {
result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
}
}
return result;
}
// This function is to be called once we have fetched a value for an attribute
// whose namespace and name match those of aAttrSelector. This function
// performs comparisons on the value only, based on aAttrSelector->mFunction.
@ -3072,7 +3044,7 @@ static PRBool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
case NS_ATTR_FUNC_INCLUDES:
return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
case NS_ATTR_FUNC_DASHMATCH:
return DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
case NS_ATTR_FUNC_ENDSMATCH:
return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
case NS_ATTR_FUNC_BEGINSMATCH:
@ -3219,8 +3191,8 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// nodes. The language itself is encoded in the LANG attribute.
const nsString* lang = data.GetLang();
if (lang && !lang->IsEmpty()) { // null check for out-of-memory
result = localTrue == DashMatchCompare(*lang,
nsDependentString(pseudoClass->mString),
result = localTrue == nsStyleUtil::DashMatchCompare(*lang,
nsDependentString(pseudoClass->mString),
nsCaseInsensitiveStringComparator());
}
else {
@ -3242,7 +3214,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
if (end == kNotFound) {
end = len;
}
if (DashMatchCompare(Substring(language, begin, end-begin),
if (nsStyleUtil::DashMatchCompare(Substring(language, begin, end-begin),
langString,
nsCaseInsensitiveStringComparator())) {
result = localTrue;

View File

@ -501,3 +501,31 @@ PRBool nsStyleUtil::IsSimpleXlink(nsIContent *aContent, nsPresContext *aPresCont
}
return rv;
}
// Compare two language strings
PRBool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue,
const nsAString& aSelectorValue,
const nsStringComparator& aComparator)
{
PRBool result;
PRUint32 selectorLen = aSelectorValue.Length();
PRUint32 attributeLen = aAttributeValue.Length();
if (selectorLen > attributeLen) {
result = PR_FALSE;
}
else {
nsAString::const_iterator iter;
if (selectorLen != attributeLen &&
*aAttributeValue.BeginReading(iter).advance(selectorLen) !=
PRUnichar('-')) {
// to match, the aAttributeValue must have a dash after the end of
// the aSelectorValue's text (unless the aSelectorValue and the
// aAttributeValue have the same text)
result = PR_FALSE;
}
else {
result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
}
}
return result;
}

View File

@ -72,6 +72,9 @@ public:
static PRBool IsHTMLLink(nsIContent *aContent, nsIAtom *aTag, nsPresContext *aPresContext, nsLinkState *aState);
static PRBool IsSimpleXlink(nsIContent *aContent, nsPresContext *aPresContext, nsLinkState *aState);
static PRBool DashMatchCompare(const nsAString& aAttributeValue,
const nsAString& aSelectorValue,
const nsStringComparator& aComparator);
};