зеркало из https://github.com/mozilla/gecko-dev.git
Fix for Bugs
19977 - Fixed crash due to misplaced TEXTAREA in TABLE. 20797 - Fixed crash caused by stray </TD>. 20645 - Fixed problem caused due to context mismatch. 22623 - Fixed by not displaying bullet for extra </LI> . 23186 - illegal content ( in TABLE ) problem. 23589 - illegal content problem. r=rickg For rickg Bugs 23451 and 23555 ( Making FONT an inline-entity..as per spec. ) r=harishd
This commit is contained in:
Родитель
83bd9a3b0e
Коммит
eccabc0bcd
|
@ -796,6 +796,19 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){
|
|||
(theType!=eToken_end) &&
|
||||
(eHTMLTag_unknown==mSkipTarget) &&
|
||||
(gHTMLElements[theTag].mSkipTarget)){ //create a new target
|
||||
// Ref: Bug# 19977
|
||||
// For optimization, determine if the skipped content is well
|
||||
// placed. This would avoid unnecessary node creation and
|
||||
// extra string append. BTW, watch out in handling the head
|
||||
// children ( especially the TITLE tag).
|
||||
if(!gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag)) {
|
||||
eHTMLTags theParentTag = mBodyContext->Last();
|
||||
PRBool theParentContains = -1;
|
||||
if(CanOmit(theParentTag,theTag,theParentContains)) {
|
||||
result=HandleOmittedTag(theToken,theTag,theParentTag,nsnull);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
mSkipTarget=gHTMLElements[theTag].mSkipTarget;
|
||||
mSkippedContent.Push(theToken);
|
||||
}
|
||||
|
@ -1085,7 +1098,7 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI
|
|||
}
|
||||
|
||||
if(theChildAgrees && theChildIsContainer) {
|
||||
if (theParentTag!=aChildTag) {
|
||||
if ((theParentTag!=aChildTag) && (nsHTMLElement::IsResidualStyleTag(aChildTag))) {
|
||||
|
||||
PRInt32 theChildIndex=GetIndexOfChildOrSynonym(*mBodyContext,aChildTag);
|
||||
|
||||
|
@ -1110,7 +1123,8 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI
|
|||
if(!(theParentContains && theChildAgrees)) {
|
||||
if (!CanPropagate(theParentTag,aChildTag,theParentContains)) {
|
||||
if(theChildIsContainer || (!theParentContains)){
|
||||
if((!theChildAgrees) && (!gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext,aChildTag))) {
|
||||
if((!theChildAgrees) && (!gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext,aChildTag)) ||
|
||||
(mBodyContext->mContextTopIndex > 0 && theIndex <= mBodyContext->mContextTopIndex)) {
|
||||
// Closing the tags above might cause non-compatible results.
|
||||
// Ex. <TABLE><TR><TD><TBODY>Text</TD></TR></TABLE>.
|
||||
// In the example above <TBODY> is badly misplaced, but
|
||||
|
@ -1286,7 +1300,9 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
CToken* theToken = aToken;
|
||||
|
||||
if(aToken) {
|
||||
PRInt32 attrCount = aToken->GetAttributeCount();
|
||||
// Note: The node for a misplaced skipped content is not yet created ( for optimization ) and hence
|
||||
// it's impossible to collect attributes. So, treat the token as though it doesn't have attibutes.
|
||||
PRInt32 attrCount = (gHTMLElements[aChildTag].mSkipTarget)? 0:aToken->GetAttributeCount();
|
||||
if((gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch)) &&
|
||||
(!nsHTMLElement::IsWhitespaceTag(aChildTag))) {
|
||||
eHTMLTags theTag=eHTMLTag_unknown;
|
||||
|
@ -1303,6 +1319,9 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
|
||||
PRBool done=PR_FALSE;
|
||||
if(theIndex>kNotFound) {
|
||||
// Avoid TD and TH getting into misplaced content stack
|
||||
// because they are legal table elements. -- Ref: Bug# 20797
|
||||
static eHTMLTags gLegalElements[]={eHTMLTag_td,eHTMLTag_th};
|
||||
while(!done){
|
||||
mMisplacedContent.Push(theToken);
|
||||
theToken->mUseCount++;
|
||||
|
@ -1316,7 +1335,9 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
theToken->mUseCount=0;
|
||||
theTag=(eHTMLTags)theToken->GetTypeID();
|
||||
if(!nsHTMLElement::IsWhitespaceTag(theTag) && theTag!=eHTMLTag_unknown) {
|
||||
if((gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) ||
|
||||
if((gHTMLElements[theTag].mSkipTarget && theToken->GetTokenType() != eToken_end) ||
|
||||
(FindTagInSet(theTag,gLegalElements,sizeof(gLegalElements)/sizeof(theTag))) ||
|
||||
(gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) ||
|
||||
(gHTMLElements[aParent].CanContain(theTag))) {
|
||||
done=PR_TRUE;
|
||||
}
|
||||
|
@ -1326,7 +1347,8 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
else done=PR_TRUE;
|
||||
}//while
|
||||
if(result==NS_OK) {
|
||||
result=HandleSavedTokens(theIndex);
|
||||
result=HandleSavedTokens(mBodyContext->mContextTopIndex=theIndex);
|
||||
mBodyContext->mContextTopIndex=0;
|
||||
}
|
||||
}//if
|
||||
}//if
|
||||
|
@ -1658,9 +1680,12 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) {
|
|||
|
||||
PopStyle(theChildTag);
|
||||
|
||||
if(gHTMLElements[theChildTag].IsMemberOf(kBlockEntity) &&
|
||||
// If the bit kHandleStrayTag is set then we automatically open up a matching
|
||||
// start tag ( compatibility ). Currently this bit is set on P tag.
|
||||
// This also fixes Bug: 22623
|
||||
if(gHTMLElements[theChildTag].HasSpecialProperty(kHandleStrayTag) &&
|
||||
mParseMode!=eParseMode_noquirks) {
|
||||
// Oh boy!! we found a "stray" block entity. Nav4.x and IE introduce line break in
|
||||
// Oh boy!! we found a "stray" tag. Nav4.x and IE introduce line break in
|
||||
// such cases. So, let's simulate that effect for compatibility.
|
||||
// Ex. <html><body>Hello</P>There</body></html>
|
||||
PRBool theParentContains=-1; //set to -1 to force canomit to recompute.
|
||||
|
@ -1735,21 +1760,19 @@ nsresult CNavDTD::HandleSavedTokens(PRInt32 anIndex) {
|
|||
theToken=(CToken*)mMisplacedContent.PopFront();
|
||||
if(theToken) {
|
||||
theTag = (eHTMLTags)theToken->GetTypeID();
|
||||
if(theTag != eHTMLTag_unknown) {
|
||||
attrCount = theToken->GetAttributeCount();
|
||||
// Put back attributes, which once got popped out, into the tokenizer
|
||||
for(PRInt32 j=0;j<attrCount; j++){
|
||||
CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront();
|
||||
if(theAttrToken) {
|
||||
mTokenizer->PushTokenFront(theAttrToken);
|
||||
}
|
||||
attrCount = (gHTMLElements[theTag].mSkipTarget)? 0:theToken->GetAttributeCount();
|
||||
// Put back attributes, which once got popped out, into the tokenizer
|
||||
for(PRInt32 j=0;j<attrCount; j++){
|
||||
CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront();
|
||||
if(theAttrToken) {
|
||||
mTokenizer->PushTokenFront(theAttrToken);
|
||||
}
|
||||
// Make sure that the BeginContext() is ended only by the call to
|
||||
// EndContext().
|
||||
if(theTag!=theParentTag || eToken_end!=theToken->GetTokenType())
|
||||
result=HandleToken(theToken,mParser);
|
||||
else mTokenRecycler->RecycleToken(theToken);
|
||||
}
|
||||
// Make sure that the BeginContext() is ended only by the call to
|
||||
// EndContext().
|
||||
if(theTag!=theParentTag || eToken_end!=theToken->GetTokenType())
|
||||
result=HandleToken(theToken,mParser);
|
||||
else mTokenRecycler->RecycleToken(theToken);
|
||||
}
|
||||
theBadTokenCount--;
|
||||
}//while
|
||||
|
|
|
@ -341,6 +341,7 @@ nsDTDContext::nsDTDContext() : mStack() {
|
|||
|
||||
MOZ_COUNT_CTOR(nsDTDContext);
|
||||
mResidualStyleCount=0;
|
||||
mContextTopIndex=0;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
memset(mXTags,0,sizeof(mXTags));
|
||||
|
|
|
@ -157,6 +157,7 @@ public:
|
|||
|
||||
nsEntryStack mStack; //this will hold a list of tagentries...
|
||||
PRInt32 mResidualStyleCount;
|
||||
PRInt32 mContextTopIndex;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
enum { eMaxTags = 100 };
|
||||
|
|
|
@ -900,8 +900,8 @@ void InitializeElementTable(void) {
|
|||
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
|
||||
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
|
||||
/*autoclose starttags and endtags*/ 0,0,0,0,
|
||||
/*parent,incl,exclgroups*/ kBlock, kInlineEntity, kNone, //this used to contain FLOW. But it's really an inline container.
|
||||
/*special props, prop-range*/ 0,kDefaultPropRange, //otherwise it tries to contain things like H1..H6
|
||||
/*parent,incl,exclgroups*/ kBlock, kInlineEntity, kNone, //this used to contain FLOW. But it's really an inline container.
|
||||
/*special props, prop-range*/ kHandleStrayTag,kDefaultPropRange, //otherwise it tries to contain things like H1..H6
|
||||
/*special parents,kids,skip*/ 0,&gInP,eHTMLTag_unknown);
|
||||
|
||||
Initialize(
|
||||
|
@ -1038,7 +1038,7 @@ void InitializeElementTable(void) {
|
|||
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
|
||||
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
|
||||
/*autoclose starttags and endtags*/ 0,0,0,0,
|
||||
/*parent,incl,exclgroups*/ kBlockEntity, (kInlineEntity|kSelf|kFlowEntity), kNone,
|
||||
/*parent,incl,exclgroups*/ kInlineEntity, (kInlineEntity|kSelf|kFlowEntity), kNone,
|
||||
/*special props, prop-range*/ 0,kDefaultPropRange,
|
||||
/*special parents,kids,skip*/ 0,0,eHTMLTag_unknown);
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ static const int kNoStyleLeaksOut = 0x0080;
|
|||
static const int kMustCloseSelf = 0x0100;
|
||||
static const int kSaveMisplaced = 0x0200; //If set, then children this tag can't contain are pushed onto the misplaced stack
|
||||
static const int kNonContainer = 0x0400; //If set, then this tag is not a container.
|
||||
static const int kHandleStrayTag = 0x0800; //If set, we automatically open a start tag
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -796,6 +796,19 @@ nsresult CNavDTD::HandleToken(CToken* aToken,nsIParser* aParser){
|
|||
(theType!=eToken_end) &&
|
||||
(eHTMLTag_unknown==mSkipTarget) &&
|
||||
(gHTMLElements[theTag].mSkipTarget)){ //create a new target
|
||||
// Ref: Bug# 19977
|
||||
// For optimization, determine if the skipped content is well
|
||||
// placed. This would avoid unnecessary node creation and
|
||||
// extra string append. BTW, watch out in handling the head
|
||||
// children ( especially the TITLE tag).
|
||||
if(!gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag)) {
|
||||
eHTMLTags theParentTag = mBodyContext->Last();
|
||||
PRBool theParentContains = -1;
|
||||
if(CanOmit(theParentTag,theTag,theParentContains)) {
|
||||
result=HandleOmittedTag(theToken,theTag,theParentTag,nsnull);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
mSkipTarget=gHTMLElements[theTag].mSkipTarget;
|
||||
mSkippedContent.Push(theToken);
|
||||
}
|
||||
|
@ -1085,7 +1098,7 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI
|
|||
}
|
||||
|
||||
if(theChildAgrees && theChildIsContainer) {
|
||||
if (theParentTag!=aChildTag) {
|
||||
if ((theParentTag!=aChildTag) && (nsHTMLElement::IsResidualStyleTag(aChildTag))) {
|
||||
|
||||
PRInt32 theChildIndex=GetIndexOfChildOrSynonym(*mBodyContext,aChildTag);
|
||||
|
||||
|
@ -1110,7 +1123,8 @@ nsresult CNavDTD::HandleDefaultStartToken(CToken* aToken,eHTMLTags aChildTag,nsI
|
|||
if(!(theParentContains && theChildAgrees)) {
|
||||
if (!CanPropagate(theParentTag,aChildTag,theParentContains)) {
|
||||
if(theChildIsContainer || (!theParentContains)){
|
||||
if((!theChildAgrees) && (!gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext,aChildTag))) {
|
||||
if((!theChildAgrees) && (!gHTMLElements[aChildTag].CanAutoCloseTag(*mBodyContext,aChildTag)) ||
|
||||
(mBodyContext->mContextTopIndex > 0 && theIndex <= mBodyContext->mContextTopIndex)) {
|
||||
// Closing the tags above might cause non-compatible results.
|
||||
// Ex. <TABLE><TR><TD><TBODY>Text</TD></TR></TABLE>.
|
||||
// In the example above <TBODY> is badly misplaced, but
|
||||
|
@ -1286,7 +1300,9 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
CToken* theToken = aToken;
|
||||
|
||||
if(aToken) {
|
||||
PRInt32 attrCount = aToken->GetAttributeCount();
|
||||
// Note: The node for a misplaced skipped content is not yet created ( for optimization ) and hence
|
||||
// it's impossible to collect attributes. So, treat the token as though it doesn't have attibutes.
|
||||
PRInt32 attrCount = (gHTMLElements[aChildTag].mSkipTarget)? 0:aToken->GetAttributeCount();
|
||||
if((gHTMLElements[aParent].HasSpecialProperty(kBadContentWatch)) &&
|
||||
(!nsHTMLElement::IsWhitespaceTag(aChildTag))) {
|
||||
eHTMLTags theTag=eHTMLTag_unknown;
|
||||
|
@ -1303,6 +1319,9 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
|
||||
PRBool done=PR_FALSE;
|
||||
if(theIndex>kNotFound) {
|
||||
// Avoid TD and TH getting into misplaced content stack
|
||||
// because they are legal table elements. -- Ref: Bug# 20797
|
||||
static eHTMLTags gLegalElements[]={eHTMLTag_td,eHTMLTag_th};
|
||||
while(!done){
|
||||
mMisplacedContent.Push(theToken);
|
||||
theToken->mUseCount++;
|
||||
|
@ -1316,7 +1335,9 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
theToken->mUseCount=0;
|
||||
theTag=(eHTMLTags)theToken->GetTypeID();
|
||||
if(!nsHTMLElement::IsWhitespaceTag(theTag) && theTag!=eHTMLTag_unknown) {
|
||||
if((gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) ||
|
||||
if((gHTMLElements[theTag].mSkipTarget && theToken->GetTokenType() != eToken_end) ||
|
||||
(FindTagInSet(theTag,gLegalElements,sizeof(gLegalElements)/sizeof(theTag))) ||
|
||||
(gHTMLElements[theTag].HasSpecialProperty(kBadContentWatch)) ||
|
||||
(gHTMLElements[aParent].CanContain(theTag))) {
|
||||
done=PR_TRUE;
|
||||
}
|
||||
|
@ -1326,7 +1347,8 @@ nsresult CNavDTD::HandleOmittedTag(CToken* aToken,eHTMLTags aChildTag,eHTMLTags
|
|||
else done=PR_TRUE;
|
||||
}//while
|
||||
if(result==NS_OK) {
|
||||
result=HandleSavedTokens(theIndex);
|
||||
result=HandleSavedTokens(mBodyContext->mContextTopIndex=theIndex);
|
||||
mBodyContext->mContextTopIndex=0;
|
||||
}
|
||||
}//if
|
||||
}//if
|
||||
|
@ -1658,9 +1680,12 @@ nsresult CNavDTD::HandleEndToken(CToken* aToken) {
|
|||
|
||||
PopStyle(theChildTag);
|
||||
|
||||
if(gHTMLElements[theChildTag].IsMemberOf(kBlockEntity) &&
|
||||
// If the bit kHandleStrayTag is set then we automatically open up a matching
|
||||
// start tag ( compatibility ). Currently this bit is set on P tag.
|
||||
// This also fixes Bug: 22623
|
||||
if(gHTMLElements[theChildTag].HasSpecialProperty(kHandleStrayTag) &&
|
||||
mParseMode!=eParseMode_noquirks) {
|
||||
// Oh boy!! we found a "stray" block entity. Nav4.x and IE introduce line break in
|
||||
// Oh boy!! we found a "stray" tag. Nav4.x and IE introduce line break in
|
||||
// such cases. So, let's simulate that effect for compatibility.
|
||||
// Ex. <html><body>Hello</P>There</body></html>
|
||||
PRBool theParentContains=-1; //set to -1 to force canomit to recompute.
|
||||
|
@ -1735,21 +1760,19 @@ nsresult CNavDTD::HandleSavedTokens(PRInt32 anIndex) {
|
|||
theToken=(CToken*)mMisplacedContent.PopFront();
|
||||
if(theToken) {
|
||||
theTag = (eHTMLTags)theToken->GetTypeID();
|
||||
if(theTag != eHTMLTag_unknown) {
|
||||
attrCount = theToken->GetAttributeCount();
|
||||
// Put back attributes, which once got popped out, into the tokenizer
|
||||
for(PRInt32 j=0;j<attrCount; j++){
|
||||
CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront();
|
||||
if(theAttrToken) {
|
||||
mTokenizer->PushTokenFront(theAttrToken);
|
||||
}
|
||||
attrCount = (gHTMLElements[theTag].mSkipTarget)? 0:theToken->GetAttributeCount();
|
||||
// Put back attributes, which once got popped out, into the tokenizer
|
||||
for(PRInt32 j=0;j<attrCount; j++){
|
||||
CToken* theAttrToken = (CToken*)mMisplacedContent.PopFront();
|
||||
if(theAttrToken) {
|
||||
mTokenizer->PushTokenFront(theAttrToken);
|
||||
}
|
||||
// Make sure that the BeginContext() is ended only by the call to
|
||||
// EndContext().
|
||||
if(theTag!=theParentTag || eToken_end!=theToken->GetTokenType())
|
||||
result=HandleToken(theToken,mParser);
|
||||
else mTokenRecycler->RecycleToken(theToken);
|
||||
}
|
||||
// Make sure that the BeginContext() is ended only by the call to
|
||||
// EndContext().
|
||||
if(theTag!=theParentTag || eToken_end!=theToken->GetTokenType())
|
||||
result=HandleToken(theToken,mParser);
|
||||
else mTokenRecycler->RecycleToken(theToken);
|
||||
}
|
||||
theBadTokenCount--;
|
||||
}//while
|
||||
|
|
|
@ -341,6 +341,7 @@ nsDTDContext::nsDTDContext() : mStack() {
|
|||
|
||||
MOZ_COUNT_CTOR(nsDTDContext);
|
||||
mResidualStyleCount=0;
|
||||
mContextTopIndex=0;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
memset(mXTags,0,sizeof(mXTags));
|
||||
|
|
|
@ -157,6 +157,7 @@ public:
|
|||
|
||||
nsEntryStack mStack; //this will hold a list of tagentries...
|
||||
PRInt32 mResidualStyleCount;
|
||||
PRInt32 mContextTopIndex;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
enum { eMaxTags = 100 };
|
||||
|
|
|
@ -900,8 +900,8 @@ void InitializeElementTable(void) {
|
|||
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
|
||||
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
|
||||
/*autoclose starttags and endtags*/ 0,0,0,0,
|
||||
/*parent,incl,exclgroups*/ kBlock, kInlineEntity, kNone, //this used to contain FLOW. But it's really an inline container.
|
||||
/*special props, prop-range*/ 0,kDefaultPropRange, //otherwise it tries to contain things like H1..H6
|
||||
/*parent,incl,exclgroups*/ kBlock, kInlineEntity, kNone, //this used to contain FLOW. But it's really an inline container.
|
||||
/*special props, prop-range*/ kHandleStrayTag,kDefaultPropRange, //otherwise it tries to contain things like H1..H6
|
||||
/*special parents,kids,skip*/ 0,&gInP,eHTMLTag_unknown);
|
||||
|
||||
Initialize(
|
||||
|
@ -1038,7 +1038,7 @@ void InitializeElementTable(void) {
|
|||
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
|
||||
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
|
||||
/*autoclose starttags and endtags*/ 0,0,0,0,
|
||||
/*parent,incl,exclgroups*/ kBlockEntity, (kInlineEntity|kSelf|kFlowEntity), kNone,
|
||||
/*parent,incl,exclgroups*/ kInlineEntity, (kInlineEntity|kSelf|kFlowEntity), kNone,
|
||||
/*special props, prop-range*/ 0,kDefaultPropRange,
|
||||
/*special parents,kids,skip*/ 0,0,eHTMLTag_unknown);
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ static const int kNoStyleLeaksOut = 0x0080;
|
|||
static const int kMustCloseSelf = 0x0100;
|
||||
static const int kSaveMisplaced = 0x0200; //If set, then children this tag can't contain are pushed onto the misplaced stack
|
||||
static const int kNonContainer = 0x0400; //If set, then this tag is not a container.
|
||||
static const int kHandleStrayTag = 0x0800; //If set, we automatically open a start tag
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче