blob: 4e8721e7349d01a1e61a1a63d3d6908efaa19143 [file] [log] [blame]
/*
* Copyright (C) 2012 Google, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "core/frame/UseCounter.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/StyleSheetContents.h"
#include "core/dom/Document.h"
#include "core/dom/ExecutionContext.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/FrameHost.h"
#include "core/frame/LocalFrame.h"
#include "core/inspector/ConsoleMessage.h"
#include "public/platform/Platform.h"
namespace blink {
int UseCounter::m_muteCount = 0;
void UseCounter::muteForInspector()
{
UseCounter::m_muteCount++;
}
void UseCounter::unmuteForInspector()
{
UseCounter::m_muteCount--;
}
UseCounter::UseCounter()
{
m_CSSFeatureBits.ensureSize(lastCSSProperty + 1);
m_CSSFeatureBits.clearAll();
}
UseCounter::~UseCounter()
{
// We always log PageDestruction so that we have a scale for the rest of the features.
blink::Platform::current()->histogramEnumeration("WebCore.FeatureObserver", PageDestruction, NumberOfFeatures);
updateMeasurements();
}
void UseCounter::updateMeasurements()
{
blink::Platform::current()->histogramEnumeration("WebCore.FeatureObserver", PageVisits, NumberOfFeatures);
if (m_countBits) {
for (unsigned i = 0; i < NumberOfFeatures; ++i) {
if (m_countBits->quickGet(i))
blink::Platform::current()->histogramEnumeration("WebCore.FeatureObserver", i, NumberOfFeatures);
}
// Clearing count bits is timing sensitive.
m_countBits->clearAll();
}
m_CSSFeatureBits.clearAll();
}
void UseCounter::didCommitLoad()
{
updateMeasurements();
}
void UseCounter::count(const Document& document, Feature feature)
{
FrameHost* host = document.frameHost();
if (!host)
return;
ASSERT(host->useCounter().deprecationMessage(feature).isEmpty());
host->useCounter().recordMeasurement(feature);
}
void UseCounter::count(const ExecutionContext* context, Feature feature)
{
if (!context)
return;
count(*toDocument(context), feature);
}
void UseCounter::countDeprecation(ExecutionContext* context, Feature feature)
{
if (!context)
return;
UseCounter::countDeprecation(*toDocument(context), feature);
}
void UseCounter::countDeprecation(const LocalDOMWindow* window, Feature feature)
{
if (!window || !window->document())
return;
UseCounter::countDeprecation(*window->document(), feature);
}
void UseCounter::countDeprecation(const Document& document, Feature feature)
{
FrameHost* host = document.frameHost();
LocalFrame* frame = document.frame();
if (!host || !frame)
return;
if (host->useCounter().recordMeasurement(feature)) {
ASSERT(!host->useCounter().deprecationMessage(feature).isEmpty());
frame->console().addMessage(ConsoleMessage::create(DeprecationMessageSource, WarningMessageLevel, host->useCounter().deprecationMessage(feature)));
}
}
// FIXME: Update other UseCounter::deprecationMessage() cases to use this.
static String replacedBy(const char* oldString, const char* newString)
{
return String::format("'%s' is deprecated. Please use '%s' instead.", oldString, newString);
}
String UseCounter::deprecationMessage(Feature feature)
{
switch (feature) {
// Quota
case PrefixedStorageInfo:
return "'window.webkitStorageInfo' is deprecated. Please use 'navigator.webkitTemporaryStorage' or 'navigator.webkitPersistentStorage' instead.";
// Keyboard Event (DOM Level 3)
case KeyboardEventKeyLocation:
return replacedBy("KeyboardEvent.keyLocation", "KeyboardEvent.location");
case ConsoleMarkTimeline:
return "console.markTimeline is deprecated. Please use the console.timeStamp instead.";
case FileError:
return "FileError is deprecated. Please use the 'name' or 'message' attributes of DOMError rather than 'code'.";
case CSSStyleSheetInsertRuleOptionalArg:
return "Calling CSSStyleSheet.insertRule() with one argument is deprecated. Please pass the index argument as well: insertRule(x, 0).";
case PrefixedVideoSupportsFullscreen:
return "'HTMLVideoElement.webkitSupportsFullscreen' is deprecated. Its value is true if the video is loaded.";
case PrefixedVideoDisplayingFullscreen:
return "'HTMLVideoElement.webkitDisplayingFullscreen' is deprecated. Please use the 'fullscreenchange' and 'webkitfullscreenchange' events instead.";
case PrefixedVideoEnterFullscreen:
return "'HTMLVideoElement.webkitEnterFullscreen()' is deprecated. Please use 'Element.requestFullscreen()' and 'Element.webkitRequestFullscreen()' instead.";
case PrefixedVideoExitFullscreen:
return "'HTMLVideoElement.webkitExitFullscreen()' is deprecated. Please use 'Document.exitFullscreen()' and 'Document.webkitExitFullscreen()' instead.";
case PrefixedVideoEnterFullScreen:
return "'HTMLVideoElement.webkitEnterFullScreen()' is deprecated. Please use 'Element.requestFullscreen()' and 'Element.webkitRequestFullscreen()' instead.";
case PrefixedVideoExitFullScreen:
return "'HTMLVideoElement.webkitExitFullScreen()' is deprecated. Please use 'Document.exitFullscreen()' and 'Document.webkitExitFullscreen()' instead.";
case MediaErrorEncrypted:
return "'MediaError.MEDIA_ERR_ENCRYPTED' is deprecated. This error code is never used.";
case PrefixedIndexedDB:
return replacedBy("webkitIndexedDB", "indexedDB");
case PrefixedIDBCursorConstructor:
return replacedBy("webkitIDBCursor", "IDBCursor");
case PrefixedIDBDatabaseConstructor:
return replacedBy("webkitIDBDatabase", "IDBDatabase");
case PrefixedIDBFactoryConstructor:
return replacedBy("webkitIDBFactory", "IDBFactory");
case PrefixedIDBIndexConstructor:
return replacedBy("webkitIDBIndex", "IDBIndex");
case PrefixedIDBKeyRangeConstructor:
return replacedBy("webkitIDBKeyRange", "IDBKeyRange");
case PrefixedIDBObjectStoreConstructor:
return replacedBy("webkitIDBObjectStore", "IDBObjectStore");
case PrefixedIDBRequestConstructor:
return replacedBy("webkitIDBRequest", "IDBRequest");
case PrefixedIDBTransactionConstructor:
return replacedBy("webkitIDBTransaction", "IDBTransaction");
case PrefixedRequestAnimationFrame:
return "'webkitRequestAnimationFrame' is vendor-specific. Please use the standard 'requestAnimationFrame' instead.";
case PrefixedCancelAnimationFrame:
return "'webkitCancelAnimationFrame' is vendor-specific. Please use the standard 'cancelAnimationFrame' instead.";
case PrefixedCancelRequestAnimationFrame:
return "'webkitCancelRequestAnimationFrame' is vendor-specific. Please use the standard 'cancelAnimationFrame' instead.";
case DocumentCreateAttributeNS:
return "'Document.createAttributeNS' is deprecated and has been removed from DOM4 (http://w3.org/tr/dom).";
case AttributeOwnerElement:
return "'Attr.ownerElement' is deprecated and has been removed from DOM4 (http://w3.org/tr/dom).";
case AttrNodeValue:
return replacedBy("Attr.nodeValue", "value");
case AttrTextContent:
return replacedBy("Attr.textContent", "value");
case RangeDetach:
return "'Range.detach' is now a no-op, as per DOM (http://dom.spec.whatwg.org/#dom-range-detach).";
case OverflowChangedEvent:
return "The 'overflowchanged' event is deprecated and may be removed. Please do not use it.";
case HTMLHeadElementProfile:
return "'HTMLHeadElement.profile' is deprecated. The reflected attribute has no effect.";
case ElementSetPrefix:
return "Setting 'Element.prefix' is deprecated, as it is read-only per DOM (http://dom.spec.whatwg.org/#element).";
case OpenWebDatabaseInWorker:
return "'openDatabase' in Workers is deprecated. Please switch to Indexed Database API.";
case OpenWebDatabaseSyncInWorker:
return "'openDatabaseSync' is deprecated. Please switch to Indexed Database API.";
case WebSocketURL:
return "'WebSocket.URL' is deprecated. Please use 'WebSocket.url' instead.";
case PictureSourceSrc:
return "<source src> with a <picture> parent is invalid and therefore ignored. Please use <source srcset> instead.";
// Features that aren't deprecated don't have a deprecation message.
default:
return String();
}
}
void UseCounter::count(CSSParserContext context, CSSPropertyID feature)
{
ASSERT(feature >= firstCSSProperty);
ASSERT(feature <= lastCSSProperty);
ASSERT(!isInternalProperty(feature));
m_CSSFeatureBits.quickSet(feature);
}
void UseCounter::count(Feature feature)
{
ASSERT(deprecationMessage(feature).isEmpty());
recordMeasurement(feature);
}
UseCounter* UseCounter::getFrom(const Document* document)
{
if (document && document->frameHost())
return &document->frameHost()->useCounter();
return 0;
}
UseCounter* UseCounter::getFrom(const CSSStyleSheet* sheet)
{
if (sheet)
return getFrom(sheet->contents());
return 0;
}
UseCounter* UseCounter::getFrom(const StyleSheetContents* sheetContents)
{
// FIXME: We may want to handle stylesheets that have multiple owners
// http://crbug.com/242125
if (sheetContents && sheetContents->hasSingleOwnerNode())
return getFrom(sheetContents->singleOwnerDocument());
return 0;
}
} // namespace blink