Chromium Code Reviews| Index: third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp |
| diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp |
| index a57d2f7ce6434ef5f6b226d2b4a847ed5ff1232b..35e54032a3cd22a73d00f493909c0cf159fcce23 100644 |
| --- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp |
| +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp |
| @@ -68,7 +68,8 @@ namespace blink { |
| SVGImage::SVGImage(ImageObserver* observer) |
| : Image(observer), |
| paint_controller_(PaintController::Create()), |
| - has_pending_timeline_rewind_(false) {} |
| + has_pending_timeline_rewind_(false), |
| + weak_ptr_factory_(this) {} |
| SVGImage::~SVGImage() { |
| if (page_) { |
| @@ -605,6 +606,43 @@ void SVGImage::UpdateUseCounters(const Document& document) const { |
| } |
| } |
| +// SVGImageLocalFrameClient is used to wait until SVG document's load event |
| +// in the case where there are subresources asynchronously loaded. |
| +class SVGImage::SVGImageLocalFrameClient : public EmptyLocalFrameClient { |
| + public: |
| + SVGImageLocalFrameClient(WeakPtr<SVGImage> image) : image_(image) {} |
| + |
| + private: |
| + void DispatchDidHandleOnloadEvents() override { |
| + // The SVGImage is destructed before SVG load completion. |
|
fs
2017/05/05 10:52:42
Nit: s/is/was/
hiroshige
2017/05/08 17:22:06
Done.
|
| + if (!image_) |
| + return; |
| + |
| + image_->LoadCompleted(); |
| + } |
| + WeakPtr<SVGImage> image_; |
| +}; |
| + |
| +void SVGImage::LoadCompleted() { |
| + switch (load_state_) { |
| + case kInDataChanged: |
| + load_state_ = kLoadCompletedSynchronously; |
| + break; |
| + |
| + case kWaitingForAsyncLoadCompletion: |
| + load_state_ = kLoadCompletedAsynchronously; |
| + if (GetImageObserver()) |
| + GetImageObserver()->LoadCompleted(this); |
| + break; |
| + |
| + case kDataChangedNotStarted: |
| + case kLoadCompletedSynchronously: |
| + case kLoadCompletedAsynchronously: |
| + CHECK(false); |
| + break; |
| + } |
| +} |
| + |
| Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) { |
| TRACE_EVENT0("blink", "SVGImage::dataChanged"); |
| @@ -612,60 +650,63 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) { |
| if (!Data()->size()) |
| return kSizeAvailable; |
| - if (all_data_received) { |
| - // SVGImage will fire events (and the default C++ handlers run) but doesn't |
| - // actually allow script to run so it's fine to call into it. We allow this |
| - // since it means an SVG data url can synchronously load like other image |
| - // types. |
| - EventDispatchForbiddenScope::AllowUserAgentEvents allow_user_agent_events; |
| - |
| - DEFINE_STATIC_LOCAL(LocalFrameClient, dummy_local_frame_client, |
| - (EmptyLocalFrameClient::Create())); |
| - |
| - CHECK(!page_); |
| - |
| - Page::PageClients page_clients; |
| - FillWithEmptyClients(page_clients); |
| - chrome_client_ = SVGImageChromeClient::Create(this); |
| - page_clients.chrome_client = chrome_client_.Get(); |
| - |
| - // FIXME: If this SVG ends up loading itself, we might leak the world. |
| - // The Cache code does not know about ImageResources holding Frames and |
| - // won't know to break the cycle. |
| - // This will become an issue when SVGImage will be able to load other |
| - // SVGImage objects, but we're safe now, because SVGImage can only be |
| - // loaded by a top-level document. |
| - Page* page; |
| - { |
| - TRACE_EVENT0("blink", "SVGImage::dataChanged::createPage"); |
| - page = Page::Create(page_clients); |
| - page->GetSettings().SetScriptEnabled(false); |
| - page->GetSettings().SetPluginsEnabled(false); |
| - page->GetSettings().SetAcceleratedCompositingEnabled(false); |
| - |
| - // Because this page is detached, it can't get default font settings |
| - // from the embedder. Copy over font settings so we have sensible |
| - // defaults. These settings are fixed and will not update if changed. |
| - if (!Page::OrdinaryPages().IsEmpty()) { |
| - Settings& default_settings = |
| - (*Page::OrdinaryPages().begin())->GetSettings(); |
| - page->GetSettings().GetGenericFontFamilySettings() = |
| - default_settings.GetGenericFontFamilySettings(); |
| - page->GetSettings().SetMinimumFontSize( |
| - default_settings.GetMinimumFontSize()); |
| - page->GetSettings().SetMinimumLogicalFontSize( |
| - default_settings.GetMinimumLogicalFontSize()); |
| - page->GetSettings().SetDefaultFontSize( |
| - default_settings.GetDefaultFontSize()); |
| - page->GetSettings().SetDefaultFixedFontSize( |
| - default_settings.GetDefaultFixedFontSize()); |
| - } |
| + if (!all_data_received) |
| + return page_ ? kSizeAvailable : kSizeUnavailable; |
| + |
| + CHECK(!page_); |
| + |
| + // SVGImage will fire events (and the default C++ handlers run) but doesn't |
| + // actually allow script to run so it's fine to call into it. We allow this |
| + // since it means an SVG data url can synchronously load like other image |
| + // types. |
| + EventDispatchForbiddenScope::AllowUserAgentEvents allow_user_agent_events; |
| + |
| + CHECK_EQ(load_state_, kDataChangedNotStarted); |
| + load_state_ = kInDataChanged; |
| + |
| + Page::PageClients page_clients; |
| + FillWithEmptyClients(page_clients); |
| + chrome_client_ = SVGImageChromeClient::Create(this); |
| + page_clients.chrome_client = chrome_client_.Get(); |
| + |
| + // FIXME: If this SVG ends up loading itself, we might leak the world. |
| + // The Cache code does not know about ImageResources holding Frames and |
| + // won't know to break the cycle. |
| + // This will become an issue when SVGImage will be able to load other |
| + // SVGImage objects, but we're safe now, because SVGImage can only be |
| + // loaded by a top-level document. |
| + Page* page; |
| + { |
| + TRACE_EVENT0("blink", "SVGImage::dataChanged::createPage"); |
| + page = Page::Create(page_clients); |
| + page->GetSettings().SetScriptEnabled(false); |
| + page->GetSettings().SetPluginsEnabled(false); |
| + page->GetSettings().SetAcceleratedCompositingEnabled(false); |
| + |
| + // Because this page is detached, it can't get default font settings |
| + // from the embedder. Copy over font settings so we have sensible |
| + // defaults. These settings are fixed and will not update if changed. |
| + if (!Page::OrdinaryPages().IsEmpty()) { |
| + Settings& default_settings = |
| + (*Page::OrdinaryPages().begin())->GetSettings(); |
| + page->GetSettings().GetGenericFontFamilySettings() = |
| + default_settings.GetGenericFontFamilySettings(); |
| + page->GetSettings().SetMinimumFontSize( |
| + default_settings.GetMinimumFontSize()); |
| + page->GetSettings().SetMinimumLogicalFontSize( |
| + default_settings.GetMinimumLogicalFontSize()); |
| + page->GetSettings().SetDefaultFontSize( |
| + default_settings.GetDefaultFontSize()); |
| + page->GetSettings().SetDefaultFixedFontSize( |
| + default_settings.GetDefaultFixedFontSize()); |
| + } |
| } |
| LocalFrame* frame = nullptr; |
| { |
| TRACE_EVENT0("blink", "SVGImage::dataChanged::createFrame"); |
| - frame = LocalFrame::Create(&dummy_local_frame_client, *page, 0); |
| + frame = LocalFrame::Create( |
| + new SVGImageLocalFrameClient(this->AsWeakPtr()), *page, 0); |
| frame->SetView(FrameView::Create(*frame)); |
| frame->Init(); |
| } |
| @@ -691,9 +732,25 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) { |
| // Set the concrete object size before a container size is available. |
| intrinsic_size_ = RoundedIntSize(ConcreteObjectSize(FloatSize( |
| LayoutReplaced::kDefaultWidth, LayoutReplaced::kDefaultHeight))); |
| + |
| + DCHECK(page_); |
| + switch (load_state_) { |
| + case kInDataChanged: |
| + load_state_ = kWaitingForAsyncLoadCompletion; |
| + return kSizeAvailableAndLoadingAsynchronously; |
| + |
| + case kLoadCompletedSynchronously: |
| + return kSizeAvailable; |
| + |
| + case kDataChangedNotStarted: |
| + case kWaitingForAsyncLoadCompletion: |
| + case kLoadCompletedAsynchronously: |
| + CHECK(false); |
| + break; |
| } |
| - return page_ ? kSizeAvailable : kSizeUnavailable; |
| + NOTREACHED(); |
| + return kSizeAvailable; |
| } |
| String SVGImage::FilenameExtension() const { |