mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 216563 - implement <svg:switch>.
Patch by scootermorris@comcast.net, r=afri, sr=dbaron
This commit is contained in:
parent
1466e099f5
commit
0c326e84e7
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -61,6 +61,7 @@ REQUIRES = xpcom \
|
||||
imglib2 \
|
||||
js \
|
||||
xpconnect \
|
||||
unicharutil \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user