Source

Target

Commits (16)
Showing with 198 additions and 124 deletions
......@@ -345,6 +345,7 @@ Mao Yujie <maojie0924@gmail.com>
Mao Yujie <yujie.mao@intel.com>
Marco Rodrigues <gothicx@gmail.com>
Mario Sanchez Prada <mario.prada@samsung.com>
Mariusz Mlynski <marius.mlynski@gmail.com>
Mark Hahnenberg <mhahnenb@andrew.cmu.edu>
Mark Seaborn <mrs@mythic-beasts.com>
Martijn Croonen <martijn@martijnc.be>
......
......@@ -68,32 +68,29 @@ bool AppCacheBackendImpl::SelectCache(
const int64 cache_document_was_loaded_from,
const GURL& manifest_url) {
AppCacheHost* host = GetHost(host_id);
if (!host || host->was_select_cache_called())
if (!host)
return false;
host->SelectCache(document_url, cache_document_was_loaded_from,
return host->SelectCache(document_url, cache_document_was_loaded_from,
manifest_url);
return true;
}
bool AppCacheBackendImpl::SelectCacheForWorker(
int host_id, int parent_process_id, int parent_host_id) {
AppCacheHost* host = GetHost(host_id);
if (!host || host->was_select_cache_called())
if (!host)
return false;
host->SelectCacheForWorker(parent_process_id, parent_host_id);
return true;
return host->SelectCacheForWorker(parent_process_id, parent_host_id);
}
bool AppCacheBackendImpl::SelectCacheForSharedWorker(
int host_id, int64 appcache_id) {
AppCacheHost* host = GetHost(host_id);
if (!host || host->was_select_cache_called())
if (!host)
return false;
host->SelectCacheForSharedWorker(appcache_id);
return true;
return host->SelectCacheForSharedWorker(appcache_id);
}
bool AppCacheBackendImpl::MarkAsForeignEntry(
......@@ -104,8 +101,7 @@ bool AppCacheBackendImpl::MarkAsForeignEntry(
if (!host)
return false;
host->MarkAsForeignEntry(document_url, cache_document_was_loaded_from);
return true;
return host->MarkAsForeignEntry(document_url, cache_document_was_loaded_from);
}
bool AppCacheBackendImpl::GetStatusWithCallback(
......
......@@ -19,7 +19,8 @@ AppCacheDispatcherHost::AppCacheDispatcherHost(
: BrowserMessageFilter(AppCacheMsgStart),
appcache_service_(appcache_service),
frontend_proxy_(this),
process_id_(process_id) {
process_id_(process_id),
weak_factory_(this) {
}
void AppCacheDispatcherHost::OnChannelConnected(int32 peer_pid) {
......@@ -28,13 +29,13 @@ void AppCacheDispatcherHost::OnChannelConnected(int32 peer_pid) {
appcache_service_.get(), &frontend_proxy_, process_id_);
get_status_callback_ =
base::Bind(&AppCacheDispatcherHost::GetStatusCallback,
base::Unretained(this));
weak_factory_.GetWeakPtr());
start_update_callback_ =
base::Bind(&AppCacheDispatcherHost::StartUpdateCallback,
base::Unretained(this));
weak_factory_.GetWeakPtr());
swap_cache_callback_ =
base::Bind(&AppCacheDispatcherHost::SwapCacheCallback,
base::Unretained(this));
weak_factory_.GetWeakPtr());
}
}
......
......@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "content/browser/appcache/appcache_backend_impl.h"
#include "content/browser/appcache/appcache_frontend_proxy.h"
......@@ -69,6 +70,8 @@ class AppCacheDispatcherHost : public BrowserMessageFilter {
// The corresponding ChildProcessHost object's id().
int process_id_;
base::WeakPtrFactory<AppCacheDispatcherHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AppCacheDispatcherHost);
};
......
......@@ -80,18 +80,21 @@ void AppCacheHost::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void AppCacheHost::SelectCache(const GURL& document_url,
bool AppCacheHost::SelectCache(const GURL& document_url,
const int64 cache_document_was_loaded_from,
const GURL& manifest_url) {
if (was_select_cache_called_)
return false;
DCHECK(pending_start_update_callback_.is_null() &&
pending_swap_cache_callback_.is_null() &&
pending_get_status_callback_.is_null() &&
!is_selection_pending() && !was_select_cache_called_);
!is_selection_pending());
was_select_cache_called_ = true;
if (!is_cache_selection_enabled_) {
FinishCacheSelection(NULL, NULL);
return;
return true;
}
origin_in_use_ = document_url.GetOrigin();
......@@ -111,7 +114,7 @@ void AppCacheHost::SelectCache(const GURL& document_url,
if (cache_document_was_loaded_from != kAppCacheNoCacheId) {
LoadSelectedCache(cache_document_was_loaded_from);
return;
return true;
}
if (!manifest_url.is_empty() &&
......@@ -132,7 +135,7 @@ void AppCacheHost::SelectCache(const GURL& document_url,
0,
false /*is_cross_origin*/));
frontend_->OnContentBlocked(host_id_, manifest_url);
return;
return true;
}
// Note: The client detects if the document was not loaded using HTTP GET
......@@ -141,49 +144,62 @@ void AppCacheHost::SelectCache(const GURL& document_url,
set_preferred_manifest_url(manifest_url);
new_master_entry_url_ = document_url;
LoadOrCreateGroup(manifest_url);
return;
return true;
}
// TODO(michaeln): If there was a manifest URL, the user agent may report
// to the user that it was ignored, to aid in application development.
FinishCacheSelection(NULL, NULL);
return true;
}
void AppCacheHost::SelectCacheForWorker(int parent_process_id,
bool AppCacheHost::SelectCacheForWorker(int parent_process_id,
int parent_host_id) {
if (was_select_cache_called_)
return false;
DCHECK(pending_start_update_callback_.is_null() &&
pending_swap_cache_callback_.is_null() &&
pending_get_status_callback_.is_null() &&
!is_selection_pending() && !was_select_cache_called_);
!is_selection_pending());
was_select_cache_called_ = true;
parent_process_id_ = parent_process_id;
parent_host_id_ = parent_host_id;
FinishCacheSelection(NULL, NULL);
return true;
}
void AppCacheHost::SelectCacheForSharedWorker(int64 appcache_id) {
bool AppCacheHost::SelectCacheForSharedWorker(int64 appcache_id) {
if (was_select_cache_called_)
return false;
DCHECK(pending_start_update_callback_.is_null() &&
pending_swap_cache_callback_.is_null() &&
pending_get_status_callback_.is_null() &&
!is_selection_pending() && !was_select_cache_called_);
!is_selection_pending());
was_select_cache_called_ = true;
if (appcache_id != kAppCacheNoCacheId) {
LoadSelectedCache(appcache_id);
return;
return true;
}
FinishCacheSelection(NULL, NULL);
return true;
}
// TODO(michaeln): change method name to MarkEntryAsForeign for consistency
void AppCacheHost::MarkAsForeignEntry(const GURL& document_url,
bool AppCacheHost::MarkAsForeignEntry(const GURL& document_url,
int64 cache_document_was_loaded_from) {
if (was_select_cache_called_)
return false;
// The document url is not the resource url in the fallback case.
storage()->MarkEntryAsForeign(
main_resource_was_namespace_entry_ ? namespace_entry_url_ : document_url,
cache_document_was_loaded_from);
SelectCache(document_url, kAppCacheNoCacheId, GURL());
return true;
}
void AppCacheHost::GetStatusWithCallback(const GetStatusCallback& callback,
......
......@@ -33,6 +33,7 @@ FORWARD_DECLARE_TEST(AppCacheHostTest, SetSwappableCache);
FORWARD_DECLARE_TEST(AppCacheHostTest, ForDedicatedWorker);
FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheAllowed);
FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheBlocked);
FORWARD_DECLARE_TEST(AppCacheHostTest, SelectCacheTwice);
FORWARD_DECLARE_TEST(AppCacheTest, CleanupUnusedCache);
class AppCache;
class AppCacheFrontend;
......@@ -76,13 +77,13 @@ class CONTENT_EXPORT AppCacheHost
void RemoveObserver(Observer* observer);
// Support for cache selection and scriptable method calls.
void SelectCache(const GURL& document_url,
bool SelectCache(const GURL& document_url,
const int64 cache_document_was_loaded_from,
const GURL& manifest_url);
void SelectCacheForWorker(int parent_process_id,
bool SelectCacheForWorker(int parent_process_id,
int parent_host_id);
void SelectCacheForSharedWorker(int64 appcache_id);
void MarkAsForeignEntry(const GURL& document_url,
bool SelectCacheForSharedWorker(int64 appcache_id);
bool MarkAsForeignEntry(const GURL& document_url,
int64 cache_document_was_loaded_from);
void GetStatusWithCallback(const GetStatusCallback& callback,
void* callback_param);
......@@ -163,7 +164,6 @@ class CONTENT_EXPORT AppCacheHost
AppCacheStorage* storage() const { return storage_; }
AppCacheFrontend* frontend() const { return frontend_; }
AppCache* associated_cache() const { return associated_cache_.get(); }
bool was_select_cache_called() const { return was_select_cache_called_; }
void enable_cache_selection(bool enable) {
is_cache_selection_enabled_ = enable;
......@@ -336,6 +336,7 @@ class CONTENT_EXPORT AppCacheHost
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, ForDedicatedWorker);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheAllowed);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheBlocked);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheHostTest, SelectCacheTwice);
FRIEND_TEST_ALL_PREFIXES(content::AppCacheTest, CleanupUnusedCache);
DISALLOW_COPY_AND_ASSIGN(AppCacheHost);
......
......@@ -530,4 +530,17 @@ TEST_F(AppCacheHostTest, SelectCacheBlocked) {
service_.set_quota_manager_proxy(NULL);
}
TEST_F(AppCacheHostTest, SelectCacheTwice) {
AppCacheHost host(1, &mock_frontend_, &service_);
const GURL kDocAndOriginUrl(GURL("http://whatever/").GetOrigin());
EXPECT_TRUE(host.SelectCache(kDocAndOriginUrl, kAppCacheNoCacheId, GURL()));
// Select methods should bail if cache has already been selected.
EXPECT_FALSE(host.SelectCache(kDocAndOriginUrl, kAppCacheNoCacheId, GURL()));
EXPECT_FALSE(host.SelectCacheForWorker(0, 0));
EXPECT_FALSE(host.SelectCacheForSharedWorker(kAppCacheNoCacheId));
EXPECT_FALSE(host.MarkAsForeignEntry(kDocAndOriginUrl, kAppCacheNoCacheId));
}
} // namespace content
......@@ -405,11 +405,13 @@ AppCacheUpdateJob::~AppCacheUpdateJob() {
if (internal_state_ != COMPLETED)
Cancel();
DCHECK(!manifest_fetcher_);
DCHECK(pending_url_fetches_.empty());
DCHECK(!inprogress_cache_.get());
DCHECK(pending_master_entries_.empty());
DCHECK(master_entry_fetches_.empty());
// The job must not outlive any of its fetchers.
CHECK(!manifest_fetcher_);
CHECK(pending_url_fetches_.empty());
CHECK(master_entry_fetches_.empty());
if (group_)
group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE);
......@@ -426,6 +428,9 @@ void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
DCHECK(!new_master_resource.has_ref());
DCHECK(new_master_resource.GetOrigin() == manifest_url_.GetOrigin());
if (ContainsKey(failed_master_entries_, new_master_resource))
return;
// Cannot add more to this update if already terminating.
if (IsTerminating()) {
group_->QueueUpdate(host, new_master_resource);
......@@ -863,6 +868,8 @@ void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(
}
hosts.clear();
failed_master_entries_.insert(url);
const char* kFormatString = "Manifest fetch failed (%d) %s";
std::string message = FormatUrlErrorMessage(
kFormatString, request->url(), fetcher->result(), response_code);
......@@ -1105,10 +1112,10 @@ void AppCacheUpdateJob::OnDestructionImminent(AppCacheHost* host) {
// The host is about to be deleted; remove from our collection.
PendingMasters::iterator found =
pending_master_entries_.find(host->pending_master_entry_url());
DCHECK(found != pending_master_entries_.end());
CHECK(found != pending_master_entries_.end());
PendingHosts& hosts = found->second;
PendingHosts::iterator it = std::find(hosts.begin(), hosts.end(), host);
DCHECK(it != hosts.end());
CHECK(it != hosts.end());
hosts.erase(it);
}
......
......@@ -283,6 +283,7 @@ class CONTENT_EXPORT AppCacheUpdateJob
PendingMasters pending_master_entries_;
size_t master_entries_completed_;
std::set<GURL> failed_master_entries_;
// TODO(jennb): Delete when update no longer fetches master entries directly.
// Helper containers to track which pending master entries have yet to be
......
......@@ -188,14 +188,14 @@ ResultExpr GpuBrokerProcessPolicy::EvaluateSyscall(int sysno) const {
#if !defined(__aarch64__)
case __NR_access:
case __NR_open:
#endif // !defined(__aarch64__)
case __NR_faccessat:
case __NR_openat:
#if !defined(OS_CHROMEOS)
// The broker process needs to able to unlink the temporary
// files that it may create. This is used by DRI3.
case __NR_unlink:
#endif
#endif // !defined(__aarch64__)
case __NR_faccessat:
case __NR_openat:
return Allow();
default:
return GpuProcessPolicy::EvaluateSyscall(sysno);
......
......@@ -42,52 +42,19 @@ void AudioClock::WroteAudio(int frames_written,
//
// The ordering of compute -> push -> pop eliminates unnecessary memory
// reallocations in cases where |buffered_| gets emptied.
const int64_t original_buffered_frames = total_buffered_frames_;
int64_t frames_played =
std::max(INT64_C(0), total_buffered_frames_ - delay_frames);
front_timestamp_ += ComputeBufferedMediaTime(frames_played);
PushBufferedAudioData(frames_written, playback_rate);
PushBufferedAudioData(frames_requested - frames_written, 0.0);
PopBufferedAudioData(frames_played);
// Update our front and back timestamps. The back timestamp is considered the
// authoritative source of truth, so base the front timestamp on range of data
// buffered. Doing so avoids accumulation errors on the front timestamp.
back_timestamp_ += base::TimeDelta::FromMicroseconds(
frames_written * playback_rate * microseconds_per_frame_);
// Ensure something crazy hasn't happened to desync the front and back values.
DCHECK_LE(front_timestamp_.InMicroseconds(), back_timestamp_.InMicroseconds())
<< "frames_written=" << frames_written
<< ", frames_requested=" << frames_requested
<< ", delay_frames=" << delay_frames
<< ", playback_rate=" << playback_rate
<< ", frames_played=" << frames_played
<< ", original_buffered_frames=" << original_buffered_frames
<< ", total_buffered_frames_=" << total_buffered_frames_;
// Update cached values.
double scaled_frames = 0;
double scaled_frames_at_same_rate = 0;
bool found_silence = false;
for (size_t i = 0; i < buffered_.size(); ++i) {
if (buffered_[i].playback_rate == 0) {
found_silence = true;
continue;
}
// Any buffered silence breaks our contiguous stretch of audio data.
if (found_silence)
break;
scaled_frames += (buffered_[i].frames * buffered_[i].playback_rate);
if (i == 0)
scaled_frames_at_same_rate = scaled_frames;
}
contiguous_audio_data_buffered_ = base::TimeDelta::FromMicroseconds(
scaled_frames * microseconds_per_frame_);
contiguous_audio_data_buffered_at_same_rate_ =
base::TimeDelta::FromMicroseconds(scaled_frames_at_same_rate *
microseconds_per_frame_);
front_timestamp_ = back_timestamp_ - ComputeBufferedMediaDuration();
DCHECK_LE(front_timestamp_, back_timestamp_);
}
void AudioClock::CompensateForSuspendedWrites(base::TimeDelta elapsed,
......@@ -144,6 +111,34 @@ base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const {
microseconds_per_frame_);
}
void AudioClock::ContiguousAudioDataBufferedForTesting(
base::TimeDelta* total,
base::TimeDelta* same_rate_total) const {
double scaled_frames = 0;
double scaled_frames_at_same_rate = 0;
bool found_silence = false;
for (size_t i = 0; i < buffered_.size(); ++i) {
if (buffered_[i].playback_rate == 0) {
found_silence = true;
continue;
}
// Any buffered silence breaks our contiguous stretch of audio data.
if (found_silence)
break;
scaled_frames += (buffered_[i].frames * buffered_[i].playback_rate);
if (i == 0)
scaled_frames_at_same_rate = scaled_frames;
}
*total = base::TimeDelta::FromMicroseconds(scaled_frames *
microseconds_per_frame_);
*same_rate_total = base::TimeDelta::FromMicroseconds(
scaled_frames_at_same_rate * microseconds_per_frame_);
}
AudioClock::AudioData::AudioData(int64_t frames, double playback_rate)
: frames(frames), playback_rate(playback_rate) {
}
......@@ -178,16 +173,10 @@ void AudioClock::PopBufferedAudioData(int64_t frames) {
}
}
base::TimeDelta AudioClock::ComputeBufferedMediaTime(int64_t frames) const {
DCHECK_LE(frames, total_buffered_frames_);
base::TimeDelta AudioClock::ComputeBufferedMediaDuration() const {
double scaled_frames = 0;
for (size_t i = 0; i < buffered_.size() && frames > 0; ++i) {
int64_t min_frames = std::min(buffered_[i].frames, frames);
scaled_frames += min_frames * buffered_[i].playback_rate;
frames -= min_frames;
}
for (const auto& buffer : buffered_)
scaled_frames += buffer.frames * buffer.playback_rate;
return base::TimeDelta::FromMicroseconds(scaled_frames *
microseconds_per_frame_);
}
......
......@@ -95,18 +95,9 @@ class MEDIA_EXPORT AudioClock {
// |timestamp| must be within front_timestamp() and back_timestamp().
base::TimeDelta TimeUntilPlayback(base::TimeDelta timestamp) const;
// Returns the amount of contiguous media time buffered at the head of the
// audio hardware buffer. Silence introduced into the audio hardware buffer is
// treated as a break in media time.
base::TimeDelta contiguous_audio_data_buffered() const {
return contiguous_audio_data_buffered_;
}
// Same as above, but also treats changes in playback rate as a break in media
// time.
base::TimeDelta contiguous_audio_data_buffered_at_same_rate() const {
return contiguous_audio_data_buffered_at_same_rate_;
}
void ContiguousAudioDataBufferedForTesting(
base::TimeDelta* total,
base::TimeDelta* same_rate_total) const;
private:
// Even with a ridiculously high sample rate of 256kHz, using 64 bits will
......@@ -123,7 +114,7 @@ class MEDIA_EXPORT AudioClock {
// Helpers for operating on |buffered_|.
void PushBufferedAudioData(int64_t frames, double playback_rate);
void PopBufferedAudioData(int64_t frames);
base::TimeDelta ComputeBufferedMediaTime(int64_t frames) const;
base::TimeDelta ComputeBufferedMediaDuration() const;
const base::TimeDelta start_timestamp_;
const double microseconds_per_frame_;
......@@ -134,10 +125,6 @@ class MEDIA_EXPORT AudioClock {
base::TimeDelta front_timestamp_;
base::TimeDelta back_timestamp_;
// Cached results of last call to WroteAudio().
base::TimeDelta contiguous_audio_data_buffered_;
base::TimeDelta contiguous_audio_data_buffered_at_same_rate_;
DISALLOW_COPY_AND_ASSIGN(AudioClock);
};
......
......@@ -40,16 +40,21 @@ class AudioClockTest : public testing::Test {
}
int ContiguousAudioDataBufferedInDays() {
return clock_.contiguous_audio_data_buffered().InDays();
base::TimeDelta total, same_rate_total;
clock_.ContiguousAudioDataBufferedForTesting(&total, &same_rate_total);
return total.InDays();
}
int ContiguousAudioDataBufferedInMilliseconds() {
return clock_.contiguous_audio_data_buffered().InMilliseconds();
base::TimeDelta total, same_rate_total;
clock_.ContiguousAudioDataBufferedForTesting(&total, &same_rate_total);
return total.InMilliseconds();
}
int ContiguousAudioDataBufferedAtSameRateInMilliseconds() {
return clock_.contiguous_audio_data_buffered_at_same_rate()
.InMilliseconds();
base::TimeDelta total, same_rate_total;
clock_.ContiguousAudioDataBufferedForTesting(&total, &same_rate_total);
return same_rate_total.InMilliseconds();
}
const int sample_rate_;
......@@ -73,15 +78,6 @@ TEST_F(AudioClockTest, BackTimestampStartsAtStartTimestamp) {
EXPECT_EQ(expected, clock.back_timestamp());
}
TEST_F(AudioClockTest, ContiguousAudioDataBufferedStartsAtZero) {
EXPECT_EQ(base::TimeDelta(), clock_.contiguous_audio_data_buffered());
}
TEST_F(AudioClockTest, ContiguousAudioDataBufferedAtSameRateStartsAtZero) {
EXPECT_EQ(base::TimeDelta(),
clock_.contiguous_audio_data_buffered_at_same_rate());
}
TEST_F(AudioClockTest, Playback) {
// The first time we write data we should still expect our start timestamp
// due to delay.
......
......@@ -839,8 +839,8 @@ void ContainerNode::notifyNodeInsertedInternal(Node& root, NodeVector& postInser
for (Node& node : NodeTraversal::inclusiveDescendantsOf(root)) {
// As an optimization we don't notify leaf nodes when when inserting
// into detached subtrees.
if (!inDocument() && !node.isContainerNode())
// into detached subtrees that are not in a shadow tree.
if (!inDocument() && !isInShadowTree() && !node.isContainerNode())
continue;
if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node.insertedInto(this))
postInsertionNotificationTargets.append(&node);
......
......@@ -2123,6 +2123,17 @@ void Document::detach(const AttachContext& context)
if (!isActive())
return;
// Frame navigation can cause a new Document to be attached. Don't allow that, since that will
// cause a situation where LocalFrame still has a Document attached after this finishes!
// Normally, it shouldn't actually be possible to trigger navigation here. However, plugins
// (see below) can cause lots of crazy things to happen, since plugin detach involves nested
// message loops.
FrameNavigationDisabler navigationDisabler(*m_frame);
// Defer widget updates to avoid plugins trying to run script inside ScriptForbiddenScope,
// which will crash the renderer after https://crrev.com/200984
HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
// Don't allow script to run in the middle of detach() because a detaching Document is not in a
// consistent state.
ScriptForbiddenScope forbidScript;
view()->dispose();
m_markers->prepareForDestruction();
......
......@@ -787,7 +787,7 @@ inline Node::InsertionNotificationRequest Node::insertedInto(ContainerNode* inse
{
ASSERT(!childNeedsStyleInvalidation());
ASSERT(!needsStyleInvalidation());
ASSERT(insertionPoint->inDocument() || isContainerNode());
ASSERT(insertionPoint->inDocument() || insertionPoint->isInShadowTree() || isContainerNode());
if (insertionPoint->inDocument())
setFlag(InDocumentFlag);
if (parentOrShadowHostNode()->isInShadowTree())
......
......@@ -253,6 +253,8 @@ void LocalFrame::navigate(Document& originDocument, const KURL& url, bool lockBa
void LocalFrame::navigate(const FrameLoadRequest& request)
{
if (!isNavigationAllowed())
return;
m_loader.load(request);
}
......@@ -838,6 +840,7 @@ inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, FrameO
, m_eventHandler(adoptPtrWillBeNoop(new EventHandler(this)))
, m_console(FrameConsole::create(*this))
, m_inputMethodController(InputMethodController::create(*this))
, m_navigationDisableCount(0)
, m_pageZoomFactor(parentPageZoomFactor(this))
, m_textZoomFactor(parentTextZoomFactor(this))
, m_inViewSourceMode(false)
......@@ -850,4 +853,15 @@ inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, FrameO
DEFINE_WEAK_IDENTIFIER_MAP(LocalFrame);
FrameNavigationDisabler::FrameNavigationDisabler(LocalFrame& frame)
: m_frame(&frame)
{
m_frame->disableNavigation();
}
FrameNavigationDisabler::~FrameNavigationDisabler()
{
m_frame->enableNavigation();
}
} // namespace blink
......@@ -178,7 +178,11 @@ namespace blink {
// ========
bool isNavigationAllowed() const { return m_navigationDisableCount == 0; }
private:
friend class FrameNavigationDisabler;
LocalFrame(FrameLoaderClient*, FrameHost*, FrameOwner*);
// Internal Frame helper overrides:
......@@ -190,6 +194,9 @@ namespace blink {
// The rect is in the coordinate space of the frame.
PassOwnPtr<DragImage> paintIntoDragImage(const DisplayItemClientWrapper&, DisplayItem::Type, RespectImageOrientationEnum shouldRespectImageOrientation, IntRect paintingRect);
void enableNavigation() { --m_navigationDisableCount; }
void disableNavigation() { ++m_navigationDisableCount; }
mutable FrameLoader m_loader;
mutable NavigationScheduler m_navigationScheduler;
......@@ -206,6 +213,8 @@ namespace blink {
const OwnPtrWillBeMember<FrameConsole> m_console;
const OwnPtrWillBeMember<InputMethodController> m_inputMethodController;
int m_navigationDisableCount;
#if ENABLE(OILPAN)
// Oilpan: in order to reliably finalize plugin elements with
// renderer-less plugins, the frame keeps track of them. When
......@@ -305,6 +314,18 @@ namespace blink {
DEFINE_TYPE_CASTS(LocalFrame, Frame, localFrame, localFrame->isLocalFrame(), localFrame.isLocalFrame());
DECLARE_WEAK_IDENTIFIER_MAP(LocalFrame);
class FrameNavigationDisabler {
WTF_MAKE_NONCOPYABLE(FrameNavigationDisabler);
STACK_ALLOCATED();
public:
explicit FrameNavigationDisabler(LocalFrame&);
~FrameNavigationDisabler();
private:
RawPtrWillBeMember<LocalFrame> m_frame;
};
} // namespace blink
// During refactoring, there are some places where we need to do type conversions that
......
......@@ -786,6 +786,8 @@ public:
FetchAPIRequestContext = 925,
CSPSourceWildcardWouldMatchExactHost = 959,
// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.
// Also, run update_use_counter_feature_enum.py in chromium/src/tools/metrics/histograms/
......
......@@ -5,6 +5,7 @@
#include "config.h"
#include "core/frame/csp/CSPSource.h"
#include "core/frame/UseCounter.h"
#include "core/frame/csp/ContentSecurityPolicy.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/KnownPorts.h"
......@@ -44,10 +45,24 @@ bool CSPSource::schemeMatches(const KURL& url) const
bool CSPSource::hostMatches(const KURL& url) const
{
const String& host = url.host();
if (equalIgnoringCase(host, m_host))
return true;
return m_hostWildcard == HasWildcard && host.endsWith("." + m_host, TextCaseInsensitive);
Document* document = m_policy->document();
bool match;
bool equalHosts = equalIgnoringCase(host, m_host);
if (m_hostWildcard == HasWildcard) {
match = host.endsWith("." + m_host, TextCaseInsensitive);
// Chrome used to, incorrectly, match *.x.y to x.y. This was fixed, but
// the following count measures when a match fails that would have
// passed the old, incorrect style, in case a lot of sites were
// relying on that behavior.
if (document && equalHosts)
UseCounter::count(*document, UseCounter::CSPSourceWildcardWouldMatchExactHost);
} else {
match = equalHosts;
}
return match;
}
bool CSPSource::pathMatches(const KURL& url) const
......