зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1551040) for stylesheets related bustage CLOSED TREE
Backed out changeset 3822fe3e163d (bug 1551040) Backed out changeset 032025f28d8f (bug 1551040) Backed out changeset 1aeb38c2dce3 (bug 1551040)
This commit is contained in:
Родитель
41fff61b24
Коммит
c88a628881
|
@ -3556,14 +3556,12 @@ class Document : public nsINode,
|
||||||
* Defined inline in nsHTMLDocument.h
|
* Defined inline in nsHTMLDocument.h
|
||||||
*/
|
*/
|
||||||
inline nsHTMLDocument* AsHTMLDocument();
|
inline nsHTMLDocument* AsHTMLDocument();
|
||||||
inline const nsHTMLDocument* AsHTMLDocument() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts IsSVGDocument, and can't return null.
|
* Asserts IsSVGDocument, and can't return null.
|
||||||
* Defined inline in SVGDocument.h
|
* Defined inline in SVGDocument.h
|
||||||
*/
|
*/
|
||||||
inline SVGDocument* AsSVGDocument();
|
inline SVGDocument* AsSVGDocument();
|
||||||
inline const SVGDocument* AsSVGDocument() const;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a node, get a weak reference to it and append that reference to
|
* Given a node, get a weak reference to it and append that reference to
|
||||||
|
|
|
@ -68,8 +68,6 @@ class nsHTMLDocument : public mozilla::dom::Document {
|
||||||
|
|
||||||
nsContentList* GetExistingForms() const { return mForms; }
|
nsContentList* GetExistingForms() const { return mForms; }
|
||||||
|
|
||||||
bool IsPlainText() const { return mIsPlainText; }
|
|
||||||
|
|
||||||
// Returns whether an object was found for aName.
|
// Returns whether an object was found for aName.
|
||||||
bool ResolveName(JSContext* aCx, const nsAString& aName,
|
bool ResolveName(JSContext* aCx, const nsAString& aName,
|
||||||
JS::MutableHandle<JS::Value> aRetval,
|
JS::MutableHandle<JS::Value> aRetval,
|
||||||
|
@ -204,11 +202,6 @@ inline nsHTMLDocument* Document::AsHTMLDocument() {
|
||||||
return static_cast<nsHTMLDocument*>(this);
|
return static_cast<nsHTMLDocument*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const nsHTMLDocument* Document::AsHTMLDocument() const {
|
|
||||||
MOZ_ASSERT(IsHTMLOrXHTML());
|
|
||||||
return static_cast<const nsHTMLDocument*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -43,11 +43,6 @@ inline SVGDocument* Document::AsSVGDocument() {
|
||||||
return static_cast<SVGDocument*>(this);
|
return static_cast<SVGDocument*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const SVGDocument* Document::AsSVGDocument() const {
|
|
||||||
MOZ_ASSERT(IsSVGDocument());
|
|
||||||
return static_cast<const SVGDocument*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<iframe src="1551040.txt"></iframe>
|
|
|
@ -1 +0,0 @@
|
||||||
Foobar
|
|
|
@ -2079,8 +2079,6 @@ skip-if(!asyncPan) == 1544895.html 1544895-ref.html
|
||||||
== 1546856-2.html 1546856-ref.html
|
== 1546856-2.html 1546856-ref.html
|
||||||
== 1547759-1.html 1547759-1-ref.html
|
== 1547759-1.html 1547759-1-ref.html
|
||||||
== 1548809.html 1548809-ref.html
|
== 1548809.html 1548809-ref.html
|
||||||
test-pref(ui.systemUsesDarkTheme,1) != 1551040.txt 1551040.txt
|
|
||||||
test-pref(ui.systemUsesDarkTheme,1) == 1551040.html 1551040.html
|
|
||||||
!= 1552789-1.html 1552789-ref-1.html
|
!= 1552789-1.html 1552789-ref-1.html
|
||||||
pref(image.downscale-during-decode.enabled,true) skip-if(Android&&webrender) == 1553571-1.html 1553571-1-ref.html
|
pref(image.downscale-during-decode.enabled,true) skip-if(Android&&webrender) == 1553571-1.html 1553571-1-ref.html
|
||||||
== 1558937-1.html 1558937-1-ref.html
|
== 1558937-1.html 1558937-1-ref.html
|
||||||
|
|
|
@ -6,11 +6,8 @@
|
||||||
|
|
||||||
#include "mozilla/dom/CSSMozDocumentRule.h"
|
#include "mozilla/dom/CSSMozDocumentRule.h"
|
||||||
#include "mozilla/dom/CSSMozDocumentRuleBinding.h"
|
#include "mozilla/dom/CSSMozDocumentRuleBinding.h"
|
||||||
|
|
||||||
#include "mozilla/dom/BrowsingContext.h"
|
|
||||||
#include "mozilla/ServoBindings.h"
|
#include "mozilla/ServoBindings.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsHTMLDocument.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
@ -70,12 +67,6 @@ bool CSSMozDocumentRule::Match(const Document* aDoc, nsIURI* aDocURI,
|
||||||
return nsContentUtils::IsPatternMatching(spec, regex, aDoc)
|
return nsContentUtils::IsPatternMatching(spec, regex, aDoc)
|
||||||
.valueOr(false);
|
.valueOr(false);
|
||||||
}
|
}
|
||||||
case DocumentMatchingFunction::PlainTextDocument:
|
|
||||||
return aDoc->IsHTMLOrXHTML() && aDoc->AsHTMLDocument()->IsPlainText();
|
|
||||||
case DocumentMatchingFunction::UnobservableDocument: {
|
|
||||||
const BrowsingContext* bc = aDoc->GetBrowsingContext();
|
|
||||||
return bc && bc->IsTop() && !bc->HasOpener();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MOZ_ASSERT_UNREACHABLE("Unknown matching function");
|
MOZ_ASSERT_UNREACHABLE("Unknown matching function");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -20,8 +20,6 @@ enum class DocumentMatchingFunction {
|
||||||
Domain,
|
Domain,
|
||||||
RegExp,
|
RegExp,
|
||||||
MediaDocument,
|
MediaDocument,
|
||||||
PlainTextDocument,
|
|
||||||
UnobservableDocument,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace css
|
} // namespace css
|
||||||
|
|
|
@ -1142,7 +1142,7 @@ already_AddRefed<StyleSheet> StyleSheet::CreateEmptyChildSheet(
|
||||||
// (3) The stylesheet is a chrome stylesheet, since those can use
|
// (3) The stylesheet is a chrome stylesheet, since those can use
|
||||||
// -moz-bool-pref, which needs to access the pref service, which is not
|
// -moz-bool-pref, which needs to access the pref service, which is not
|
||||||
// threadsafe.
|
// threadsafe.
|
||||||
static bool AllowParallelParse(css::Loader& aLoader, URLExtraData* aUrlData) {
|
static bool AllowParallelParse(css::Loader& aLoader, nsIURI* aSheetURI) {
|
||||||
// If the browser is recording CSS errors, we need to use the sequential path
|
// If the browser is recording CSS errors, we need to use the sequential path
|
||||||
// because the parallel path doesn't support that.
|
// because the parallel path doesn't support that.
|
||||||
Document* doc = aLoader.GetDocument();
|
Document* doc = aLoader.GetDocument();
|
||||||
|
@ -1157,7 +1157,7 @@ static bool AllowParallelParse(css::Loader& aLoader, URLExtraData* aUrlData) {
|
||||||
//
|
//
|
||||||
// Note that UA stylesheets can also use -moz-bool-pref, but those are always
|
// Note that UA stylesheets can also use -moz-bool-pref, but those are always
|
||||||
// parsed sync.
|
// parsed sync.
|
||||||
if (aUrlData->ChromeRulesEnabled()) {
|
if (dom::IsChromeURI(aSheetURI)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1179,7 +1179,7 @@ RefPtr<StyleSheetParsePromise> StyleSheet::ParseSheet(
|
||||||
: StyleAllowImportRules::Yes;
|
: StyleAllowImportRules::Yes;
|
||||||
const bool shouldRecordCounters =
|
const bool shouldRecordCounters =
|
||||||
aLoader.GetDocument() && aLoader.GetDocument()->GetStyleUseCounters();
|
aLoader.GetDocument() && aLoader.GetDocument()->GetStyleUseCounters();
|
||||||
if (!AllowParallelParse(aLoader, Inner().mURLData)) {
|
if (!AllowParallelParse(aLoader, GetSheetURI())) {
|
||||||
UniquePtr<StyleUseCounters> counters =
|
UniquePtr<StyleUseCounters> counters =
|
||||||
shouldRecordCounters ? Servo_UseCounters_Create().Consume() : nullptr;
|
shouldRecordCounters ? Servo_UseCounters_Create().Consume() : nullptr;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ void URLExtraData::Init() {
|
||||||
sDummyChrome =
|
sDummyChrome =
|
||||||
new URLExtraData(baseURI.forget(), referrerInfo.forget(),
|
new URLExtraData(baseURI.forget(), referrerInfo.forget(),
|
||||||
NullPrincipal::CreateWithoutOriginAttributes());
|
NullPrincipal::CreateWithoutOriginAttributes());
|
||||||
sDummyChrome->mChromeRulesEnabled = true;
|
sDummyChrome->mIsChrome = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
|
|
@ -34,8 +34,7 @@ struct URLExtraData {
|
||||||
// When we hold the URI data of a style sheet, referrer is always
|
// When we hold the URI data of a style sheet, referrer is always
|
||||||
// equal to the sheet URI.
|
// equal to the sheet URI.
|
||||||
nsCOMPtr<nsIURI> referrer = mReferrerInfo->GetOriginalReferrer();
|
nsCOMPtr<nsIURI> referrer = mReferrerInfo->GetOriginalReferrer();
|
||||||
mChromeRulesEnabled = referrer && (referrer->SchemeIs("chrome") ||
|
mIsChrome = referrer ? dom::IsChromeURI(referrer) : false;
|
||||||
referrer->SchemeIs("resource"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
URLExtraData(nsIURI* aBaseURI, nsIReferrerInfo* aReferrerInfo,
|
URLExtraData(nsIURI* aBaseURI, nsIReferrerInfo* aReferrerInfo,
|
||||||
|
@ -49,8 +48,6 @@ struct URLExtraData {
|
||||||
nsIReferrerInfo* ReferrerInfo() const { return mReferrerInfo; }
|
nsIReferrerInfo* ReferrerInfo() const { return mReferrerInfo; }
|
||||||
nsIPrincipal* Principal() const { return mPrincipal; }
|
nsIPrincipal* Principal() const { return mPrincipal; }
|
||||||
|
|
||||||
bool ChromeRulesEnabled() const { return mChromeRulesEnabled; }
|
|
||||||
|
|
||||||
static URLExtraData* Dummy() {
|
static URLExtraData* Dummy() {
|
||||||
MOZ_ASSERT(sDummy);
|
MOZ_ASSERT(sDummy);
|
||||||
return sDummy;
|
return sDummy;
|
||||||
|
@ -76,7 +73,8 @@ struct URLExtraData {
|
||||||
nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
|
nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
|
||||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||||
|
|
||||||
bool mChromeRulesEnabled;
|
// True if referrer is a chrome:// URI.
|
||||||
|
bool mIsChrome;
|
||||||
|
|
||||||
static StaticRefPtr<URLExtraData> sDummy;
|
static StaticRefPtr<URLExtraData> sDummy;
|
||||||
static StaticRefPtr<URLExtraData> sDummyChrome;
|
static StaticRefPtr<URLExtraData> sDummyChrome;
|
||||||
|
|
|
@ -17,16 +17,6 @@ html:not([dir]) pre { /* Not a UA sheet, so doesn't use :-moz-has-dir-attr */
|
||||||
unicode-bidi: plaintext;
|
unicode-bidi: plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-moz-document unobservable-document() {
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
/* in-content-page-{color, background} for dark theme. */
|
|
||||||
background: #2a2a2e;
|
|
||||||
color: rgb(249, 249, 250);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE(emilio): For some reason some pages, mainly bing.com, load a bunch of
|
/* NOTE(emilio): For some reason some pages, mainly bing.com, load a bunch of
|
||||||
* scripts in zero-size <object> elements, see bug 1548449.
|
* scripts in zero-size <object> elements, see bug 1548449.
|
||||||
*
|
*
|
||||||
|
|
|
@ -12,8 +12,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=814907
|
||||||
@-moz-document media-document(image) {}
|
@-moz-document media-document(image) {}
|
||||||
@-moz-document media-document(plugin) {}
|
@-moz-document media-document(plugin) {}
|
||||||
@-moz-document media-document(all) {}
|
@-moz-document media-document(all) {}
|
||||||
@-moz-document plain-text-document() {}
|
|
||||||
@-moz-document unobservable-document() {}
|
|
||||||
|
|
||||||
@-moz-document url(http://www.example.com/) {}
|
@-moz-document url(http://www.example.com/) {}
|
||||||
@-moz-document url('http://www.example.com/') {}
|
@-moz-document url('http://www.example.com/') {}
|
||||||
|
@ -62,8 +60,6 @@ function runTest()
|
||||||
"media-document(image)",
|
"media-document(image)",
|
||||||
"media-document(plugin)",
|
"media-document(plugin)",
|
||||||
"media-document(all)",
|
"media-document(all)",
|
||||||
"plain-text-document()",
|
|
||||||
"unobservable-document()",
|
|
||||||
"url(\"http://www.example.com/\")",
|
"url(\"http://www.example.com/\")",
|
||||||
"url(\"http://www.example.com/\")",
|
"url(\"http://www.example.com/\")",
|
||||||
"url(\"http://www.example.com/\")",
|
"url(\"http://www.example.com/\")",
|
||||||
|
|
|
@ -140,7 +140,7 @@ impl<'a> ParserContext<'a> {
|
||||||
/// Returns whether chrome-only rules should be parsed.
|
/// Returns whether chrome-only rules should be parsed.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn chrome_rules_enabled(&self) -> bool {
|
pub fn chrome_rules_enabled(&self) -> bool {
|
||||||
self.url_data.chrome_rules_enabled() || self.stylesheet_origin == Origin::User
|
self.url_data.is_chrome() || self.stylesheet_origin == Origin::User
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether we're in a user-agent stylesheet or chrome rules are enabled.
|
/// Whether we're in a user-agent stylesheet or chrome rules are enabled.
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl<'a> SelectorParser<'a> {
|
||||||
/// Whether we're parsing selectors in a stylesheet that has chrome
|
/// Whether we're parsing selectors in a stylesheet that has chrome
|
||||||
/// privilege.
|
/// privilege.
|
||||||
pub fn chrome_rules_enabled(&self) -> bool {
|
pub fn chrome_rules_enabled(&self) -> bool {
|
||||||
self.url_data.map_or(false, |d| d.chrome_rules_enabled()) || self.stylesheet_origin == Origin::User
|
self.url_data.map_or(false, |d| d.is_chrome()) || self.stylesheet_origin == Origin::User
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,13 +110,6 @@ pub enum DocumentMatchingFunction {
|
||||||
/// Matching function for a media document.
|
/// Matching function for a media document.
|
||||||
#[css(function)]
|
#[css(function)]
|
||||||
MediaDocument(MediaDocumentKind),
|
MediaDocument(MediaDocumentKind),
|
||||||
/// Matching function for a plain-text document.
|
|
||||||
#[css(function)]
|
|
||||||
PlainTextDocument(()),
|
|
||||||
/// Matching function for a document that can be observed by other content
|
|
||||||
/// documents.
|
|
||||||
#[css(function)]
|
|
||||||
UnobservableDocument(()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! parse_quoted_or_unquoted_string {
|
macro_rules! parse_quoted_or_unquoted_string {
|
||||||
|
@ -168,21 +161,6 @@ impl DocumentMatchingFunction {
|
||||||
Ok(DocumentMatchingFunction::MediaDocument(kind))
|
Ok(DocumentMatchingFunction::MediaDocument(kind))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
"plain-text-document" => {
|
|
||||||
input.parse_nested_block(|input| {
|
|
||||||
input.expect_exhausted()?;
|
|
||||||
Ok(DocumentMatchingFunction::PlainTextDocument(()))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
"unobservable-document" => {
|
|
||||||
input.parse_nested_block(|input| {
|
|
||||||
input.expect_exhausted()?;
|
|
||||||
Ok(DocumentMatchingFunction::UnobservableDocument(()))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
Err(location.new_custom_error(
|
Err(location.new_custom_error(
|
||||||
StyleParseErrorKind::UnexpectedFunction(function.clone())
|
StyleParseErrorKind::UnexpectedFunction(function.clone())
|
||||||
|
@ -206,8 +184,6 @@ impl DocumentMatchingFunction {
|
||||||
DocumentMatchingFunction::MediaDocument(_) => {
|
DocumentMatchingFunction::MediaDocument(_) => {
|
||||||
GeckoDocumentMatchingFunction::MediaDocument
|
GeckoDocumentMatchingFunction::MediaDocument
|
||||||
},
|
},
|
||||||
DocumentMatchingFunction::PlainTextDocument(..) => GeckoDocumentMatchingFunction::PlainTextDocument,
|
|
||||||
DocumentMatchingFunction::UnobservableDocument(..) => GeckoDocumentMatchingFunction::UnobservableDocument,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let pattern = nsCStr::from(match *self {
|
let pattern = nsCStr::from(match *self {
|
||||||
|
@ -221,8 +197,6 @@ impl DocumentMatchingFunction {
|
||||||
MediaDocumentKind::Plugin => "plugin",
|
MediaDocumentKind::Plugin => "plugin",
|
||||||
MediaDocumentKind::Video => "video",
|
MediaDocumentKind::Video => "video",
|
||||||
},
|
},
|
||||||
DocumentMatchingFunction::PlainTextDocument(()) |
|
|
||||||
DocumentMatchingFunction::UnobservableDocument(()) => "",
|
|
||||||
});
|
});
|
||||||
unsafe { Gecko_DocumentRule_UseForPresentation(device.document(), &*pattern, func) }
|
unsafe { Gecko_DocumentRule_UseForPresentation(device.document(), &*pattern, func) }
|
||||||
}
|
}
|
||||||
|
@ -282,7 +256,7 @@ impl DocumentCondition {
|
||||||
use crate::stylesheets::Origin;
|
use crate::stylesheets::Origin;
|
||||||
use static_prefs::pref;
|
use static_prefs::pref;
|
||||||
|
|
||||||
if context.in_ua_or_chrome_sheet() {
|
if context.stylesheet_origin != Origin::Author {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,8 +156,8 @@ impl UrlExtraData {
|
||||||
|
|
||||||
/// True if this URL scheme is chrome.
|
/// True if this URL scheme is chrome.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn chrome_rules_enabled(&self) -> bool {
|
pub fn is_chrome(&self) -> bool {
|
||||||
self.as_ref().mChromeRulesEnabled
|
self.as_ref().mIsChrome
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a reference to this `UrlExtraData` from a reference to pointer.
|
/// Create a reference to this `UrlExtraData` from a reference to pointer.
|
||||||
|
@ -215,7 +215,7 @@ impl fmt::Debug for UrlExtraData {
|
||||||
|
|
||||||
formatter
|
formatter
|
||||||
.debug_struct("URLExtraData")
|
.debug_struct("URLExtraData")
|
||||||
.field("chrome_rules_enabled", &self.chrome_rules_enabled())
|
.field("is_chrome", &self.is_chrome())
|
||||||
.field(
|
.field(
|
||||||
"base",
|
"base",
|
||||||
&DebugURI(self.as_ref().mBaseURI.raw::<structs::nsIURI>()),
|
&DebugURI(self.as_ref().mBaseURI.raw::<structs::nsIURI>()),
|
||||||
|
|
|
@ -118,16 +118,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for () {
|
|
||||||
#[inline]
|
|
||||||
fn to_css<W>(&self, _: &mut CssWriter<W>) -> fmt::Result
|
|
||||||
where
|
|
||||||
W: Write,
|
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A writer tailored for serialising CSS.
|
/// A writer tailored for serialising CSS.
|
||||||
///
|
///
|
||||||
/// Coupled with SequenceWriter, this allows callers to transparently handle
|
/// Coupled with SequenceWriter, this allows callers to transparently handle
|
||||||
|
|
|
@ -104,10 +104,9 @@
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
/* Keep these in sync with layout/base/PresShell.cpp, and plaintext.css */
|
/* Keep this in sync with layout/base/PresShell.cpp! */
|
||||||
--in-content-page-background: #2A2A2E;
|
--in-content-page-background: #2A2A2E;
|
||||||
--in-content-page-color: rgb(249, 249, 250);
|
--in-content-page-color: rgb(249, 249, 250);
|
||||||
|
|
||||||
--in-content-text-color: var(--in-content-page-color);
|
--in-content-text-color: var(--in-content-page-color);
|
||||||
--in-content-deemphasized-text: var(--grey-40);
|
--in-content-deemphasized-text: var(--grey-40);
|
||||||
--in-content-box-background: #202023;
|
--in-content-box-background: #202023;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче