зеркало из https://github.com/mozilla/gecko-dev.git
added css loader for child sheet
added drag pseudo classes fixed background parsing bug
This commit is contained in:
Родитель
f3a9992625
Коммит
8c7207edd4
|
@ -19,6 +19,7 @@
|
||||||
#include "nsCSSProps.h"
|
#include "nsCSSProps.h"
|
||||||
#include "nsCSSKeywords.h"
|
#include "nsCSSKeywords.h"
|
||||||
#include "nsCSSScanner.h"
|
#include "nsCSSScanner.h"
|
||||||
|
#include "nsICSSLoader.h"
|
||||||
#include "nsICSSStyleRule.h"
|
#include "nsICSSStyleRule.h"
|
||||||
#include "nsIUnicharInputStream.h"
|
#include "nsIUnicharInputStream.h"
|
||||||
#include "nsIStyleSet.h"
|
#include "nsIStyleSet.h"
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
#include "nsICSSDeclaration.h"
|
#include "nsICSSDeclaration.h"
|
||||||
#include "nsStyleConsts.h"
|
#include "nsStyleConsts.h"
|
||||||
#include "nsIURL.h"
|
#include "nsIURL.h"
|
||||||
|
#include "nsIURLGroup.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsIAtom.h"
|
#include "nsIAtom.h"
|
||||||
#include "nsVoidArray.h"
|
#include "nsVoidArray.h"
|
||||||
|
@ -115,6 +117,8 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
|
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
|
||||||
|
|
||||||
|
NS_IMETHOD SetChildLoader(nsICSSLoader* aChildLoader);
|
||||||
|
|
||||||
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
|
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
|
||||||
nsIURL* aInputURL,
|
nsIURL* aInputURL,
|
||||||
nsICSSStyleSheet*& aResult);
|
nsICSSStyleSheet*& aResult);
|
||||||
|
@ -227,6 +231,8 @@ protected:
|
||||||
nsCSSScanner* mScanner;
|
nsCSSScanner* mScanner;
|
||||||
nsIURL* mURL;
|
nsIURL* mURL;
|
||||||
nsICSSStyleSheet* mSheet;
|
nsICSSStyleSheet* mSheet;
|
||||||
|
PRInt32 mChildSheetCount;
|
||||||
|
nsICSSLoader* mChildLoader; // not ref counted, it owns us
|
||||||
|
|
||||||
PRBool mInHead;
|
PRBool mInHead;
|
||||||
|
|
||||||
|
@ -255,6 +261,8 @@ CSSParserImpl::CSSParserImpl()
|
||||||
mHavePushBack = PR_FALSE;
|
mHavePushBack = PR_FALSE;
|
||||||
mNavQuirkMode = PR_TRUE;
|
mNavQuirkMode = PR_TRUE;
|
||||||
mCaseSensitive = PR_FALSE;
|
mCaseSensitive = PR_FALSE;
|
||||||
|
mChildSheetCount = 0;
|
||||||
|
mChildLoader = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
||||||
|
@ -266,6 +274,7 @@ CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
||||||
mHavePushBack = PR_FALSE;
|
mHavePushBack = PR_FALSE;
|
||||||
mNavQuirkMode = PR_TRUE;
|
mNavQuirkMode = PR_TRUE;
|
||||||
mCaseSensitive = PR_FALSE;
|
mCaseSensitive = PR_FALSE;
|
||||||
|
mChildSheetCount = mSheet->StyleSheetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
|
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
|
||||||
|
@ -296,6 +305,7 @@ CSSParserImpl::SetStyleSheet(nsICSSStyleSheet* aSheet)
|
||||||
NS_IF_RELEASE(mSheet);
|
NS_IF_RELEASE(mSheet);
|
||||||
mSheet = aSheet;
|
mSheet = aSheet;
|
||||||
NS_ADDREF(mSheet);
|
NS_ADDREF(mSheet);
|
||||||
|
mChildSheetCount = mSheet->StyleSheetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -308,6 +318,13 @@ CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
CSSParserImpl::SetChildLoader(nsICSSLoader* aChildLoader)
|
||||||
|
{
|
||||||
|
mChildLoader = aChildLoader; // not ref counted, it owns us
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
||||||
|
@ -318,6 +335,7 @@ CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
||||||
|
|
||||||
if (nsnull == mSheet) {
|
if (nsnull == mSheet) {
|
||||||
NS_NewCSSStyleSheet(&mSheet, aInputURL);
|
NS_NewCSSStyleSheet(&mSheet, aInputURL);
|
||||||
|
mChildSheetCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt32 errorCode = NS_OK;
|
PRInt32 errorCode = NS_OK;
|
||||||
|
@ -669,148 +687,35 @@ PRBool CSSParserImpl::ParseImportRule(PRInt32& aErrorCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef PRBool (*nsStringEnumFunc)(const nsString& aSubString, void *aData);
|
|
||||||
|
|
||||||
const PRUnichar kNullCh = PRUnichar('\0');
|
|
||||||
const PRUnichar kSingleQuote = PRUnichar('\'');
|
|
||||||
const PRUnichar kDoubleQuote = PRUnichar('\"');
|
|
||||||
const PRUnichar kComma = PRUnichar(',');
|
|
||||||
const PRUnichar kHyphenCh = PRUnichar('-');
|
|
||||||
|
|
||||||
static PRBool EnumerateString(const nsString& aStringList, nsStringEnumFunc aFunc, void* aData)
|
|
||||||
{
|
|
||||||
PRBool running = PR_TRUE;
|
|
||||||
|
|
||||||
nsAutoString stringList(aStringList); // copy to work buffer
|
|
||||||
nsAutoString subStr;
|
|
||||||
|
|
||||||
stringList.Append(kNullCh); // put an extra null at the end
|
|
||||||
|
|
||||||
PRUnichar* start = (PRUnichar*)(const PRUnichar*)stringList.GetUnicode();
|
|
||||||
PRUnichar* end = start;
|
|
||||||
|
|
||||||
while (running && (kNullCh != *start)) {
|
|
||||||
PRBool quoted = PR_FALSE;
|
|
||||||
|
|
||||||
while ((kNullCh != *start) && nsString::IsSpace(*start)) { // skip leading space
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((kSingleQuote == *start) || (kDoubleQuote == *start)) { // quoted string
|
|
||||||
PRUnichar quote = *start++;
|
|
||||||
quoted = PR_TRUE;
|
|
||||||
end = start;
|
|
||||||
while (kNullCh != *end) {
|
|
||||||
if (quote == *end) { // found closing quote
|
|
||||||
*end++ = kNullCh; // end string here
|
|
||||||
while ((kNullCh != *end) && (kComma != *end)) { // keep going until comma
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // non-quoted string or ended
|
|
||||||
end = start;
|
|
||||||
|
|
||||||
while ((kNullCh != *end) && (kComma != *end)) { // look for comma
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
*end = kNullCh; // end string here
|
|
||||||
}
|
|
||||||
|
|
||||||
// truncate at first non letter, digit or hyphen
|
|
||||||
PRUnichar* test = start;
|
|
||||||
while (test <= end) {
|
|
||||||
if ((PR_FALSE == nsString::IsAlpha(*test)) &&
|
|
||||||
(PR_FALSE == nsString::IsDigit(*test)) && (kHyphenCh != *test)) {
|
|
||||||
*test = kNullCh;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
test++;
|
|
||||||
}
|
|
||||||
subStr = start;
|
|
||||||
|
|
||||||
if (PR_FALSE == quoted) {
|
|
||||||
subStr.CompressWhitespace(PR_FALSE, PR_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 < subStr.Length()) {
|
|
||||||
running = (*aFunc)(subStr, aData);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = ++end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PRBool MediumEnumFunc(const nsString& aSubString, void *aData)
|
|
||||||
{
|
|
||||||
nsIAtom* medium = NS_NewAtom(aSubString);
|
|
||||||
((nsICSSStyleSheet*)aData)->AppendMedium(medium);
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
|
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
|
||||||
{
|
{
|
||||||
PRBool result = PR_FALSE;
|
PRBool result = PR_FALSE;
|
||||||
|
|
||||||
// XXX probably need a way to encode unicode junk for the part of
|
if (mChildLoader) {
|
||||||
// the url that follows a "?"
|
// XXX probably need a way to encode unicode junk for the part of
|
||||||
char* cp = aURLSpec.ToNewCString();
|
// the url that follows a "?"
|
||||||
nsIURL* url;
|
nsIURL* url;
|
||||||
aErrorCode = NS_NewURL(&url, cp, mURL);
|
nsIURLGroup* urlGroup = nsnull;
|
||||||
delete [] cp;
|
mURL->GetURLGroup(&urlGroup);
|
||||||
if (NS_FAILED(aErrorCode)) {
|
if (urlGroup) {
|
||||||
// import url is bad
|
aErrorCode = urlGroup->CreateURL(&url, mURL, aURLSpec, nsnull);
|
||||||
// XXX log this somewhere for easier web page debugging
|
NS_RELEASE(urlGroup);
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
|
|
||||||
|
|
||||||
nsIInputStream* in;
|
|
||||||
nsresult rv = NS_OpenURL(url, &in);
|
|
||||||
if (rv != NS_OK) {
|
|
||||||
// failure to make connection
|
|
||||||
// XXX log this somewhere for easier web page debugging
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
aErrorCode = NS_NewURL(&url, aURLSpec, mURL);
|
||||||
nsIUnicharInputStream* uin;
|
|
||||||
aErrorCode = NS_NewConverterStream(&uin, nsnull, in);
|
|
||||||
if (NS_FAILED(aErrorCode)) {
|
|
||||||
// XXX no iso-latin-1 converter? out of memory?
|
|
||||||
NS_RELEASE(in);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
NS_RELEASE(in);
|
|
||||||
|
|
||||||
// Create a new parse to parse the import.
|
|
||||||
|
|
||||||
nsICSSParser* parser;
|
|
||||||
aErrorCode = NS_NewCSSParser(&parser);
|
|
||||||
if (NS_SUCCEEDED(aErrorCode)) {
|
|
||||||
nsICSSStyleSheet* childSheet = nsnull;
|
|
||||||
aErrorCode = parser->Parse(uin, url, childSheet);
|
|
||||||
NS_RELEASE(parser);
|
|
||||||
if (NS_SUCCEEDED(aErrorCode) && (nsnull != childSheet)) {
|
|
||||||
if (0 < aMedia.Length()) {
|
|
||||||
EnumerateString(aMedia, MediumEnumFunc, childSheet);
|
|
||||||
}
|
|
||||||
mSheet->AppendStyleSheet(childSheet);
|
|
||||||
result = PR_TRUE;
|
|
||||||
}
|
|
||||||
NS_IF_RELEASE(childSheet);
|
|
||||||
}
|
|
||||||
NS_RELEASE(uin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NS_FAILED(aErrorCode)) {
|
||||||
|
// import url is bad
|
||||||
|
// XXX log this somewhere for easier web page debugging
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
|
||||||
|
mChildLoader->LoadChildSheet(mSheet, url, aMedia, mChildSheetCount++);
|
||||||
|
}
|
||||||
|
NS_RELEASE(url);
|
||||||
}
|
}
|
||||||
NS_RELEASE(url);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -995,6 +900,8 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom)
|
||||||
{
|
{
|
||||||
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
|
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
|
||||||
(nsCSSAtoms::disabledPseudo == aAtom) ||
|
(nsCSSAtoms::disabledPseudo == aAtom) ||
|
||||||
|
(nsCSSAtoms::dragOverPseudo == aAtom) ||
|
||||||
|
(nsCSSAtoms::dragPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::focusPseudo == aAtom) ||
|
(nsCSSAtoms::focusPseudo == aAtom) ||
|
||||||
|
@ -2698,7 +2605,7 @@ PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32& aErrorCode,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PRInt32 bit = xValue.GetIntValue();
|
PRInt32 bit = xValue.GetIntValue();
|
||||||
if (0 == bit) {
|
if (BG_CENTER == bit) {
|
||||||
// Special hack for center bits: We can have two of them
|
// Special hack for center bits: We can have two of them
|
||||||
mask |= centerBit;
|
mask |= centerBit;
|
||||||
centerBit <<= 1;
|
centerBit <<= 1;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "nsCSSProps.h"
|
#include "nsCSSProps.h"
|
||||||
#include "nsCSSKeywords.h"
|
#include "nsCSSKeywords.h"
|
||||||
#include "nsCSSScanner.h"
|
#include "nsCSSScanner.h"
|
||||||
|
#include "nsICSSLoader.h"
|
||||||
#include "nsICSSStyleRule.h"
|
#include "nsICSSStyleRule.h"
|
||||||
#include "nsIUnicharInputStream.h"
|
#include "nsIUnicharInputStream.h"
|
||||||
#include "nsIStyleSet.h"
|
#include "nsIStyleSet.h"
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
#include "nsICSSDeclaration.h"
|
#include "nsICSSDeclaration.h"
|
||||||
#include "nsStyleConsts.h"
|
#include "nsStyleConsts.h"
|
||||||
#include "nsIURL.h"
|
#include "nsIURL.h"
|
||||||
|
#include "nsIURLGroup.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsIAtom.h"
|
#include "nsIAtom.h"
|
||||||
#include "nsVoidArray.h"
|
#include "nsVoidArray.h"
|
||||||
|
@ -115,6 +117,8 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
|
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
|
||||||
|
|
||||||
|
NS_IMETHOD SetChildLoader(nsICSSLoader* aChildLoader);
|
||||||
|
|
||||||
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
|
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
|
||||||
nsIURL* aInputURL,
|
nsIURL* aInputURL,
|
||||||
nsICSSStyleSheet*& aResult);
|
nsICSSStyleSheet*& aResult);
|
||||||
|
@ -227,6 +231,8 @@ protected:
|
||||||
nsCSSScanner* mScanner;
|
nsCSSScanner* mScanner;
|
||||||
nsIURL* mURL;
|
nsIURL* mURL;
|
||||||
nsICSSStyleSheet* mSheet;
|
nsICSSStyleSheet* mSheet;
|
||||||
|
PRInt32 mChildSheetCount;
|
||||||
|
nsICSSLoader* mChildLoader; // not ref counted, it owns us
|
||||||
|
|
||||||
PRBool mInHead;
|
PRBool mInHead;
|
||||||
|
|
||||||
|
@ -255,6 +261,8 @@ CSSParserImpl::CSSParserImpl()
|
||||||
mHavePushBack = PR_FALSE;
|
mHavePushBack = PR_FALSE;
|
||||||
mNavQuirkMode = PR_TRUE;
|
mNavQuirkMode = PR_TRUE;
|
||||||
mCaseSensitive = PR_FALSE;
|
mCaseSensitive = PR_FALSE;
|
||||||
|
mChildSheetCount = 0;
|
||||||
|
mChildLoader = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
||||||
|
@ -266,6 +274,7 @@ CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
||||||
mHavePushBack = PR_FALSE;
|
mHavePushBack = PR_FALSE;
|
||||||
mNavQuirkMode = PR_TRUE;
|
mNavQuirkMode = PR_TRUE;
|
||||||
mCaseSensitive = PR_FALSE;
|
mCaseSensitive = PR_FALSE;
|
||||||
|
mChildSheetCount = mSheet->StyleSheetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
|
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
|
||||||
|
@ -296,6 +305,7 @@ CSSParserImpl::SetStyleSheet(nsICSSStyleSheet* aSheet)
|
||||||
NS_IF_RELEASE(mSheet);
|
NS_IF_RELEASE(mSheet);
|
||||||
mSheet = aSheet;
|
mSheet = aSheet;
|
||||||
NS_ADDREF(mSheet);
|
NS_ADDREF(mSheet);
|
||||||
|
mChildSheetCount = mSheet->StyleSheetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -308,6 +318,13 @@ CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
CSSParserImpl::SetChildLoader(nsICSSLoader* aChildLoader)
|
||||||
|
{
|
||||||
|
mChildLoader = aChildLoader; // not ref counted, it owns us
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
||||||
|
@ -318,6 +335,7 @@ CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
||||||
|
|
||||||
if (nsnull == mSheet) {
|
if (nsnull == mSheet) {
|
||||||
NS_NewCSSStyleSheet(&mSheet, aInputURL);
|
NS_NewCSSStyleSheet(&mSheet, aInputURL);
|
||||||
|
mChildSheetCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt32 errorCode = NS_OK;
|
PRInt32 errorCode = NS_OK;
|
||||||
|
@ -669,148 +687,35 @@ PRBool CSSParserImpl::ParseImportRule(PRInt32& aErrorCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef PRBool (*nsStringEnumFunc)(const nsString& aSubString, void *aData);
|
|
||||||
|
|
||||||
const PRUnichar kNullCh = PRUnichar('\0');
|
|
||||||
const PRUnichar kSingleQuote = PRUnichar('\'');
|
|
||||||
const PRUnichar kDoubleQuote = PRUnichar('\"');
|
|
||||||
const PRUnichar kComma = PRUnichar(',');
|
|
||||||
const PRUnichar kHyphenCh = PRUnichar('-');
|
|
||||||
|
|
||||||
static PRBool EnumerateString(const nsString& aStringList, nsStringEnumFunc aFunc, void* aData)
|
|
||||||
{
|
|
||||||
PRBool running = PR_TRUE;
|
|
||||||
|
|
||||||
nsAutoString stringList(aStringList); // copy to work buffer
|
|
||||||
nsAutoString subStr;
|
|
||||||
|
|
||||||
stringList.Append(kNullCh); // put an extra null at the end
|
|
||||||
|
|
||||||
PRUnichar* start = (PRUnichar*)(const PRUnichar*)stringList.GetUnicode();
|
|
||||||
PRUnichar* end = start;
|
|
||||||
|
|
||||||
while (running && (kNullCh != *start)) {
|
|
||||||
PRBool quoted = PR_FALSE;
|
|
||||||
|
|
||||||
while ((kNullCh != *start) && nsString::IsSpace(*start)) { // skip leading space
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((kSingleQuote == *start) || (kDoubleQuote == *start)) { // quoted string
|
|
||||||
PRUnichar quote = *start++;
|
|
||||||
quoted = PR_TRUE;
|
|
||||||
end = start;
|
|
||||||
while (kNullCh != *end) {
|
|
||||||
if (quote == *end) { // found closing quote
|
|
||||||
*end++ = kNullCh; // end string here
|
|
||||||
while ((kNullCh != *end) && (kComma != *end)) { // keep going until comma
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // non-quoted string or ended
|
|
||||||
end = start;
|
|
||||||
|
|
||||||
while ((kNullCh != *end) && (kComma != *end)) { // look for comma
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
*end = kNullCh; // end string here
|
|
||||||
}
|
|
||||||
|
|
||||||
// truncate at first non letter, digit or hyphen
|
|
||||||
PRUnichar* test = start;
|
|
||||||
while (test <= end) {
|
|
||||||
if ((PR_FALSE == nsString::IsAlpha(*test)) &&
|
|
||||||
(PR_FALSE == nsString::IsDigit(*test)) && (kHyphenCh != *test)) {
|
|
||||||
*test = kNullCh;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
test++;
|
|
||||||
}
|
|
||||||
subStr = start;
|
|
||||||
|
|
||||||
if (PR_FALSE == quoted) {
|
|
||||||
subStr.CompressWhitespace(PR_FALSE, PR_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 < subStr.Length()) {
|
|
||||||
running = (*aFunc)(subStr, aData);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = ++end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PRBool MediumEnumFunc(const nsString& aSubString, void *aData)
|
|
||||||
{
|
|
||||||
nsIAtom* medium = NS_NewAtom(aSubString);
|
|
||||||
((nsICSSStyleSheet*)aData)->AppendMedium(medium);
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
|
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
|
||||||
{
|
{
|
||||||
PRBool result = PR_FALSE;
|
PRBool result = PR_FALSE;
|
||||||
|
|
||||||
// XXX probably need a way to encode unicode junk for the part of
|
if (mChildLoader) {
|
||||||
// the url that follows a "?"
|
// XXX probably need a way to encode unicode junk for the part of
|
||||||
char* cp = aURLSpec.ToNewCString();
|
// the url that follows a "?"
|
||||||
nsIURL* url;
|
nsIURL* url;
|
||||||
aErrorCode = NS_NewURL(&url, cp, mURL);
|
nsIURLGroup* urlGroup = nsnull;
|
||||||
delete [] cp;
|
mURL->GetURLGroup(&urlGroup);
|
||||||
if (NS_FAILED(aErrorCode)) {
|
if (urlGroup) {
|
||||||
// import url is bad
|
aErrorCode = urlGroup->CreateURL(&url, mURL, aURLSpec, nsnull);
|
||||||
// XXX log this somewhere for easier web page debugging
|
NS_RELEASE(urlGroup);
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
|
|
||||||
|
|
||||||
nsIInputStream* in;
|
|
||||||
nsresult rv = NS_OpenURL(url, &in);
|
|
||||||
if (rv != NS_OK) {
|
|
||||||
// failure to make connection
|
|
||||||
// XXX log this somewhere for easier web page debugging
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
aErrorCode = NS_NewURL(&url, aURLSpec, mURL);
|
||||||
nsIUnicharInputStream* uin;
|
|
||||||
aErrorCode = NS_NewConverterStream(&uin, nsnull, in);
|
|
||||||
if (NS_FAILED(aErrorCode)) {
|
|
||||||
// XXX no iso-latin-1 converter? out of memory?
|
|
||||||
NS_RELEASE(in);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
NS_RELEASE(in);
|
|
||||||
|
|
||||||
// Create a new parse to parse the import.
|
|
||||||
|
|
||||||
nsICSSParser* parser;
|
|
||||||
aErrorCode = NS_NewCSSParser(&parser);
|
|
||||||
if (NS_SUCCEEDED(aErrorCode)) {
|
|
||||||
nsICSSStyleSheet* childSheet = nsnull;
|
|
||||||
aErrorCode = parser->Parse(uin, url, childSheet);
|
|
||||||
NS_RELEASE(parser);
|
|
||||||
if (NS_SUCCEEDED(aErrorCode) && (nsnull != childSheet)) {
|
|
||||||
if (0 < aMedia.Length()) {
|
|
||||||
EnumerateString(aMedia, MediumEnumFunc, childSheet);
|
|
||||||
}
|
|
||||||
mSheet->AppendStyleSheet(childSheet);
|
|
||||||
result = PR_TRUE;
|
|
||||||
}
|
|
||||||
NS_IF_RELEASE(childSheet);
|
|
||||||
}
|
|
||||||
NS_RELEASE(uin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NS_FAILED(aErrorCode)) {
|
||||||
|
// import url is bad
|
||||||
|
// XXX log this somewhere for easier web page debugging
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
|
||||||
|
mChildLoader->LoadChildSheet(mSheet, url, aMedia, mChildSheetCount++);
|
||||||
|
}
|
||||||
|
NS_RELEASE(url);
|
||||||
}
|
}
|
||||||
NS_RELEASE(url);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -995,6 +900,8 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom)
|
||||||
{
|
{
|
||||||
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
|
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
|
||||||
(nsCSSAtoms::disabledPseudo == aAtom) ||
|
(nsCSSAtoms::disabledPseudo == aAtom) ||
|
||||||
|
(nsCSSAtoms::dragOverPseudo == aAtom) ||
|
||||||
|
(nsCSSAtoms::dragPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::focusPseudo == aAtom) ||
|
(nsCSSAtoms::focusPseudo == aAtom) ||
|
||||||
|
@ -2698,7 +2605,7 @@ PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32& aErrorCode,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PRInt32 bit = xValue.GetIntValue();
|
PRInt32 bit = xValue.GetIntValue();
|
||||||
if (0 == bit) {
|
if (BG_CENTER == bit) {
|
||||||
// Special hack for center bits: We can have two of them
|
// Special hack for center bits: We can have two of them
|
||||||
mask |= centerBit;
|
mask |= centerBit;
|
||||||
centerBit <<= 1;
|
centerBit <<= 1;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "nsCSSProps.h"
|
#include "nsCSSProps.h"
|
||||||
#include "nsCSSKeywords.h"
|
#include "nsCSSKeywords.h"
|
||||||
#include "nsCSSScanner.h"
|
#include "nsCSSScanner.h"
|
||||||
|
#include "nsICSSLoader.h"
|
||||||
#include "nsICSSStyleRule.h"
|
#include "nsICSSStyleRule.h"
|
||||||
#include "nsIUnicharInputStream.h"
|
#include "nsIUnicharInputStream.h"
|
||||||
#include "nsIStyleSet.h"
|
#include "nsIStyleSet.h"
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
#include "nsICSSDeclaration.h"
|
#include "nsICSSDeclaration.h"
|
||||||
#include "nsStyleConsts.h"
|
#include "nsStyleConsts.h"
|
||||||
#include "nsIURL.h"
|
#include "nsIURL.h"
|
||||||
|
#include "nsIURLGroup.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsIAtom.h"
|
#include "nsIAtom.h"
|
||||||
#include "nsVoidArray.h"
|
#include "nsVoidArray.h"
|
||||||
|
@ -115,6 +117,8 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
|
NS_IMETHOD SetCaseSensitive(PRBool aCaseSensitive);
|
||||||
|
|
||||||
|
NS_IMETHOD SetChildLoader(nsICSSLoader* aChildLoader);
|
||||||
|
|
||||||
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
|
NS_IMETHOD Parse(nsIUnicharInputStream* aInput,
|
||||||
nsIURL* aInputURL,
|
nsIURL* aInputURL,
|
||||||
nsICSSStyleSheet*& aResult);
|
nsICSSStyleSheet*& aResult);
|
||||||
|
@ -227,6 +231,8 @@ protected:
|
||||||
nsCSSScanner* mScanner;
|
nsCSSScanner* mScanner;
|
||||||
nsIURL* mURL;
|
nsIURL* mURL;
|
||||||
nsICSSStyleSheet* mSheet;
|
nsICSSStyleSheet* mSheet;
|
||||||
|
PRInt32 mChildSheetCount;
|
||||||
|
nsICSSLoader* mChildLoader; // not ref counted, it owns us
|
||||||
|
|
||||||
PRBool mInHead;
|
PRBool mInHead;
|
||||||
|
|
||||||
|
@ -255,6 +261,8 @@ CSSParserImpl::CSSParserImpl()
|
||||||
mHavePushBack = PR_FALSE;
|
mHavePushBack = PR_FALSE;
|
||||||
mNavQuirkMode = PR_TRUE;
|
mNavQuirkMode = PR_TRUE;
|
||||||
mCaseSensitive = PR_FALSE;
|
mCaseSensitive = PR_FALSE;
|
||||||
|
mChildSheetCount = 0;
|
||||||
|
mChildLoader = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
||||||
|
@ -266,6 +274,7 @@ CSSParserImpl::CSSParserImpl(nsICSSStyleSheet* aSheet)
|
||||||
mHavePushBack = PR_FALSE;
|
mHavePushBack = PR_FALSE;
|
||||||
mNavQuirkMode = PR_TRUE;
|
mNavQuirkMode = PR_TRUE;
|
||||||
mCaseSensitive = PR_FALSE;
|
mCaseSensitive = PR_FALSE;
|
||||||
|
mChildSheetCount = mSheet->StyleSheetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
|
NS_IMPL_ISUPPORTS(CSSParserImpl,kICSSParserIID)
|
||||||
|
@ -296,6 +305,7 @@ CSSParserImpl::SetStyleSheet(nsICSSStyleSheet* aSheet)
|
||||||
NS_IF_RELEASE(mSheet);
|
NS_IF_RELEASE(mSheet);
|
||||||
mSheet = aSheet;
|
mSheet = aSheet;
|
||||||
NS_ADDREF(mSheet);
|
NS_ADDREF(mSheet);
|
||||||
|
mChildSheetCount = mSheet->StyleSheetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -308,6 +318,13 @@ CSSParserImpl::SetCaseSensitive(PRBool aCaseSensitive)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
CSSParserImpl::SetChildLoader(nsICSSLoader* aChildLoader)
|
||||||
|
{
|
||||||
|
mChildLoader = aChildLoader; // not ref counted, it owns us
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
||||||
|
@ -318,6 +335,7 @@ CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
|
||||||
|
|
||||||
if (nsnull == mSheet) {
|
if (nsnull == mSheet) {
|
||||||
NS_NewCSSStyleSheet(&mSheet, aInputURL);
|
NS_NewCSSStyleSheet(&mSheet, aInputURL);
|
||||||
|
mChildSheetCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt32 errorCode = NS_OK;
|
PRInt32 errorCode = NS_OK;
|
||||||
|
@ -669,148 +687,35 @@ PRBool CSSParserImpl::ParseImportRule(PRInt32& aErrorCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef PRBool (*nsStringEnumFunc)(const nsString& aSubString, void *aData);
|
|
||||||
|
|
||||||
const PRUnichar kNullCh = PRUnichar('\0');
|
|
||||||
const PRUnichar kSingleQuote = PRUnichar('\'');
|
|
||||||
const PRUnichar kDoubleQuote = PRUnichar('\"');
|
|
||||||
const PRUnichar kComma = PRUnichar(',');
|
|
||||||
const PRUnichar kHyphenCh = PRUnichar('-');
|
|
||||||
|
|
||||||
static PRBool EnumerateString(const nsString& aStringList, nsStringEnumFunc aFunc, void* aData)
|
|
||||||
{
|
|
||||||
PRBool running = PR_TRUE;
|
|
||||||
|
|
||||||
nsAutoString stringList(aStringList); // copy to work buffer
|
|
||||||
nsAutoString subStr;
|
|
||||||
|
|
||||||
stringList.Append(kNullCh); // put an extra null at the end
|
|
||||||
|
|
||||||
PRUnichar* start = (PRUnichar*)(const PRUnichar*)stringList.GetUnicode();
|
|
||||||
PRUnichar* end = start;
|
|
||||||
|
|
||||||
while (running && (kNullCh != *start)) {
|
|
||||||
PRBool quoted = PR_FALSE;
|
|
||||||
|
|
||||||
while ((kNullCh != *start) && nsString::IsSpace(*start)) { // skip leading space
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((kSingleQuote == *start) || (kDoubleQuote == *start)) { // quoted string
|
|
||||||
PRUnichar quote = *start++;
|
|
||||||
quoted = PR_TRUE;
|
|
||||||
end = start;
|
|
||||||
while (kNullCh != *end) {
|
|
||||||
if (quote == *end) { // found closing quote
|
|
||||||
*end++ = kNullCh; // end string here
|
|
||||||
while ((kNullCh != *end) && (kComma != *end)) { // keep going until comma
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // non-quoted string or ended
|
|
||||||
end = start;
|
|
||||||
|
|
||||||
while ((kNullCh != *end) && (kComma != *end)) { // look for comma
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
*end = kNullCh; // end string here
|
|
||||||
}
|
|
||||||
|
|
||||||
// truncate at first non letter, digit or hyphen
|
|
||||||
PRUnichar* test = start;
|
|
||||||
while (test <= end) {
|
|
||||||
if ((PR_FALSE == nsString::IsAlpha(*test)) &&
|
|
||||||
(PR_FALSE == nsString::IsDigit(*test)) && (kHyphenCh != *test)) {
|
|
||||||
*test = kNullCh;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
test++;
|
|
||||||
}
|
|
||||||
subStr = start;
|
|
||||||
|
|
||||||
if (PR_FALSE == quoted) {
|
|
||||||
subStr.CompressWhitespace(PR_FALSE, PR_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 < subStr.Length()) {
|
|
||||||
running = (*aFunc)(subStr, aData);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = ++end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PRBool MediumEnumFunc(const nsString& aSubString, void *aData)
|
|
||||||
{
|
|
||||||
nsIAtom* medium = NS_NewAtom(aSubString);
|
|
||||||
((nsICSSStyleSheet*)aData)->AppendMedium(medium);
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
|
PRBool CSSParserImpl::ProcessImport(PRInt32& aErrorCode, const nsString& aURLSpec, const nsString& aMedia)
|
||||||
{
|
{
|
||||||
PRBool result = PR_FALSE;
|
PRBool result = PR_FALSE;
|
||||||
|
|
||||||
// XXX probably need a way to encode unicode junk for the part of
|
if (mChildLoader) {
|
||||||
// the url that follows a "?"
|
// XXX probably need a way to encode unicode junk for the part of
|
||||||
char* cp = aURLSpec.ToNewCString();
|
// the url that follows a "?"
|
||||||
nsIURL* url;
|
nsIURL* url;
|
||||||
aErrorCode = NS_NewURL(&url, cp, mURL);
|
nsIURLGroup* urlGroup = nsnull;
|
||||||
delete [] cp;
|
mURL->GetURLGroup(&urlGroup);
|
||||||
if (NS_FAILED(aErrorCode)) {
|
if (urlGroup) {
|
||||||
// import url is bad
|
aErrorCode = urlGroup->CreateURL(&url, mURL, aURLSpec, nsnull);
|
||||||
// XXX log this somewhere for easier web page debugging
|
NS_RELEASE(urlGroup);
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
|
|
||||||
|
|
||||||
nsIInputStream* in;
|
|
||||||
nsresult rv = NS_OpenURL(url, &in);
|
|
||||||
if (rv != NS_OK) {
|
|
||||||
// failure to make connection
|
|
||||||
// XXX log this somewhere for easier web page debugging
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
aErrorCode = NS_NewURL(&url, aURLSpec, mURL);
|
||||||
nsIUnicharInputStream* uin;
|
|
||||||
aErrorCode = NS_NewConverterStream(&uin, nsnull, in);
|
|
||||||
if (NS_FAILED(aErrorCode)) {
|
|
||||||
// XXX no iso-latin-1 converter? out of memory?
|
|
||||||
NS_RELEASE(in);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
NS_RELEASE(in);
|
|
||||||
|
|
||||||
// Create a new parse to parse the import.
|
|
||||||
|
|
||||||
nsICSSParser* parser;
|
|
||||||
aErrorCode = NS_NewCSSParser(&parser);
|
|
||||||
if (NS_SUCCEEDED(aErrorCode)) {
|
|
||||||
nsICSSStyleSheet* childSheet = nsnull;
|
|
||||||
aErrorCode = parser->Parse(uin, url, childSheet);
|
|
||||||
NS_RELEASE(parser);
|
|
||||||
if (NS_SUCCEEDED(aErrorCode) && (nsnull != childSheet)) {
|
|
||||||
if (0 < aMedia.Length()) {
|
|
||||||
EnumerateString(aMedia, MediumEnumFunc, childSheet);
|
|
||||||
}
|
|
||||||
mSheet->AppendStyleSheet(childSheet);
|
|
||||||
result = PR_TRUE;
|
|
||||||
}
|
|
||||||
NS_IF_RELEASE(childSheet);
|
|
||||||
}
|
|
||||||
NS_RELEASE(uin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NS_FAILED(aErrorCode)) {
|
||||||
|
// import url is bad
|
||||||
|
// XXX log this somewhere for easier web page debugging
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PR_FALSE == mSheet->ContainsStyleSheet(url)) { // don't allow circular references
|
||||||
|
mChildLoader->LoadChildSheet(mSheet, url, aMedia, mChildSheetCount++);
|
||||||
|
}
|
||||||
|
NS_RELEASE(url);
|
||||||
}
|
}
|
||||||
NS_RELEASE(url);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -995,6 +900,8 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom)
|
||||||
{
|
{
|
||||||
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
|
return PRBool((nsCSSAtoms::activePseudo == aAtom) ||
|
||||||
(nsCSSAtoms::disabledPseudo == aAtom) ||
|
(nsCSSAtoms::disabledPseudo == aAtom) ||
|
||||||
|
(nsCSSAtoms::dragOverPseudo == aAtom) ||
|
||||||
|
(nsCSSAtoms::dragPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
||||||
(nsCSSAtoms::focusPseudo == aAtom) ||
|
(nsCSSAtoms::focusPseudo == aAtom) ||
|
||||||
|
@ -2698,7 +2605,7 @@ PRBool CSSParserImpl::ParseBackgroundPosition(PRInt32& aErrorCode,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PRInt32 bit = xValue.GetIntValue();
|
PRInt32 bit = xValue.GetIntValue();
|
||||||
if (0 == bit) {
|
if (BG_CENTER == bit) {
|
||||||
// Special hack for center bits: We can have two of them
|
// Special hack for center bits: We can have two of them
|
||||||
mask |= centerBit;
|
mask |= centerBit;
|
||||||
centerBit <<= 1;
|
centerBit <<= 1;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче