From 88c11aa4ea457b515f6e733ec608bdf72ffe3bec Mon Sep 17 00:00:00 2001 From: droger Date: Tue, 17 Feb 2015 06:10:11 -0800 Subject: [PATCH] [iOS] Upstream DomAlteringLock. BUG=452490 Review URL: https://codereview.chromium.org/927373002 Cr-Commit-Position: refs/heads/master@{#316574} --- ios/chrome/browser/web/dom_altering_lock.h | 64 +++++++++++++++++++++ ios/chrome/browser/web/dom_altering_lock.mm | 48 ++++++++++++++++ ios/chrome/ios_chrome.gyp | 2 + 3 files changed, 114 insertions(+) create mode 100644 ios/chrome/browser/web/dom_altering_lock.h create mode 100644 ios/chrome/browser/web/dom_altering_lock.mm diff --git a/ios/chrome/browser/web/dom_altering_lock.h b/ios/chrome/browser/web/dom_altering_lock.h new file mode 100644 index 00000000000000..f262c88429cf97 --- /dev/null +++ b/ios/chrome/browser/web/dom_altering_lock.h @@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_WEB_DOM_ALTERING_LOCK_H_ +#define IOS_CHROME_BROWSER_WEB_DOM_ALTERING_LOCK_H_ + +#include "base/ios/block_types.h" +#import "base/ios/weak_nsobject.h" +#include "ios/web/public/web_state/web_state_user_data.h" + +namespace web { +class WebState; +} + +typedef void (^ProceduralBlockWithBool)(BOOL); + +// This protocol must be implemented by all classes which may alter the DOM tree +// of a web page. Before altering the DOM, the class must call +// DOMAlteringLock::Acquire() and can only proceed if the lock is really +// acquired. +// After restoring the DOM tree, the class must call DOMAlteringLock::Release(). +@protocol DOMAltering + +// Method called when another class wants to acquire the lock. +// Return YES if the class is ready to restore the DOM tree to its initial state +// and release the lock. A call to |releaseDOMLockWithCompletionHandler:| +// will follow to do the actual cleaning. +// Return NO if the class wants to keep an exclusive access to the DOM tree. +// Other features must account for the fact that they may not be able to acquire +// a lock on the DOM and behave accordingly. +- (BOOL)canReleaseDOMLock; + +// Method called when another class wants to acquire the lock. +// The class must restore the DOM tree, call DOMAlteringLock::Release() and then +// |completionHandler|. +- (void)releaseDOMLockWithCompletionHandler:(ProceduralBlock)completionHandler; + +@end + +class DOMAlteringLock : public web::WebStateUserData { + public: + DOMAlteringLock(web::WebState* web_state); + + // This method must be called before altering the DOM of the page. This will + // ensure that only one class tries to alter the page at a time. + // The completion handler is called with YES if the lock was acquired, or NO + // if it could not. + // This method must be called on the UI thread. + void Acquire(id feature, ProceduralBlockWithBool lockAction); + + // Releases the lock on the DOM tree. + // The lock is always released, even if it was acquired multiple times. + // This method must be called on the UI thread. + void Release(id feature); + + private: + // DOMAltering object currently having the lock. + base::WeakNSProtocol> current_dom_altering_feature_; + + ~DOMAlteringLock() override; +}; + +#endif // IOS_CHROME_BROWSER_WEB_DOM_ALTERING_LOCK_H_ diff --git a/ios/chrome/browser/web/dom_altering_lock.mm b/ios/chrome/browser/web/dom_altering_lock.mm new file mode 100644 index 00000000000000..2d5aa49698664e --- /dev/null +++ b/ios/chrome/browser/web/dom_altering_lock.mm @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/web/dom_altering_lock.h" + +#include "base/logging.h" +#include "ios/web/public/web_thread.h" + +DEFINE_WEB_STATE_USER_DATA_KEY(DOMAlteringLock); + +DOMAlteringLock::DOMAlteringLock(web::WebState* web_state) { +} + +DOMAlteringLock::~DOMAlteringLock() { +} + +void DOMAlteringLock::Acquire(id feature, + ProceduralBlockWithBool lockAction) { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); + if (current_dom_altering_feature_.get() == feature) { + lockAction(YES); + return; + } + if (current_dom_altering_feature_) { + if (![current_dom_altering_feature_ canReleaseDOMLock]) { + lockAction(NO); + return; + } + [current_dom_altering_feature_ releaseDOMLockWithCompletionHandler:^() { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); + DCHECK(current_dom_altering_feature_.get() == nil) + << "The lock must be released before calling the completion handler."; + current_dom_altering_feature_.reset(feature); + lockAction(YES); + }]; + return; + } + current_dom_altering_feature_.reset(feature); + lockAction(YES); +} + +// Release the lock on the DOM tree. +void DOMAlteringLock::Release(id feature) { + DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); + if (current_dom_altering_feature_.get() == feature) + current_dom_altering_feature_.reset(); +} diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp index 89f7abe7b77f63..91d5a4e215aba0 100644 --- a/ios/chrome/ios_chrome.gyp +++ b/ios/chrome/ios_chrome.gyp @@ -103,6 +103,8 @@ 'browser/ui/ui_util.mm', 'browser/ui/uikit_ui_util.h', 'browser/ui/uikit_ui_util.mm', + 'browser/web/dom_altering_lock.h', + 'browser/web/dom_altering_lock.mm', 'browser/web_resource/ios_web_resource_service.cc', 'browser/web_resource/ios_web_resource_service.h', ],