blob: 3f0606fa3d7c1fa259f82ba4091b8c8cdbd13b99 [file] [log] [blame]
/*
* Copyright (C) 2011 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 APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "Internals.h"
#include "CachedResourceLoader.h"
#include "ClientRect.h"
#include "Document.h"
#include "DocumentMarker.h"
#include "DocumentMarkerController.h"
#include "Element.h"
#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameView.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "HTMLTextAreaElement.h"
#include "InspectorController.h"
#include "IntRect.h"
#include "NodeRenderingContext.h"
#include "Page.h"
#include "Range.h"
#include "RenderObject.h"
#include "RenderTreeAsText.h"
#include "Settings.h"
#include "ShadowContentElement.h"
#include "ShadowRoot.h"
#include "SpellChecker.h"
#include "TextIterator.h"
#if ENABLE(GESTURE_EVENTS)
#include "PlatformGestureEvent.h"
#endif
#if ENABLE(SMOOTH_SCROLLING)
#include "ScrollAnimator.h"
#endif
#if ENABLE(INPUT_COLOR)
#include "ColorChooser.h"
#endif
namespace WebCore {
static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result)
{
if (markerType.isEmpty() || equalIgnoringCase(markerType, "all"))
result = DocumentMarker::AllMarkers();
else if (equalIgnoringCase(markerType, "Spelling"))
result = DocumentMarker::Spelling;
else if (equalIgnoringCase(markerType, "Grammar"))
result = DocumentMarker::Grammar;
else if (equalIgnoringCase(markerType, "TextMatch"))
result = DocumentMarker::TextMatch;
else if (equalIgnoringCase(markerType, "Replacement"))
result = DocumentMarker::Replacement;
else if (equalIgnoringCase(markerType, "CorrectionIndicator"))
result = DocumentMarker::CorrectionIndicator;
else if (equalIgnoringCase(markerType, "RejectedCorrection"))
result = DocumentMarker::RejectedCorrection;
else if (equalIgnoringCase(markerType, "Autocorrected"))
result = DocumentMarker::Autocorrected;
else if (equalIgnoringCase(markerType, "SpellCheckingExemption"))
result = DocumentMarker::SpellCheckingExemption;
else if (equalIgnoringCase(markerType, "DeletedAutocorrection"))
result = DocumentMarker::DeletedAutocorrection;
else
return false;
return true;
}
static SpellChecker* spellchecker(Document* document)
{
if (!document || !document->frame() || !document->frame()->editor())
return 0;
return document->frame()->editor()->spellChecker();
}
const char* Internals::internalsId = "internals";
PassRefPtr<Internals> Internals::create()
{
return adoptRef(new Internals);
}
Internals::~Internals()
{
}
Internals::Internals()
: passwordEchoDurationInSecondsBackedUp(false)
, passwordEchoEnabledBackedUp(false)
{
}
bool Internals::isPreloaded(Document* document, const String& url)
{
if (!document)
return false;
return document->cachedResourceLoader()->isPreloaded(url);
}
PassRefPtr<Element> Internals::createShadowContentElement(Document* document, ExceptionCode& ec)
{
if (!document) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return ShadowContentElement::create(document);
}
Element* Internals::getElementByIdInShadowRoot(Node* shadowRoot, const String& id, ExceptionCode& ec)
{
if (!shadowRoot || !shadowRoot->isShadowRoot()) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return toShadowRoot(shadowRoot)->getElementById(id);
}
String Internals::elementRenderTreeAsText(Element* element, ExceptionCode& ec)
{
if (!element) {
ec = INVALID_ACCESS_ERR;
return String();
}
String representation = externalRepresentation(element);
if (representation.isEmpty()) {
ec = INVALID_ACCESS_ERR;
return String();
}
return representation;
}
Node* Internals::ensureShadowRoot(Element* host, ExceptionCode& ec)
{
if (!host) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return host->ensureShadowRoot();
}
Node* Internals::shadowRoot(Element* host, ExceptionCode& ec)
{
if (!host) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return host->shadowRoot();
}
void Internals::removeShadowRoot(Element* host, ExceptionCode& ec)
{
if (!host) {
ec = INVALID_ACCESS_ERR;
return;
}
host->removeShadowRoot();
}
Element* Internals::includerFor(Node* node, ExceptionCode& ec)
{
if (!node) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return NodeRenderingContext(node).includer();
}
String Internals::shadowPseudoId(Element* element, ExceptionCode& ec)
{
if (!element) {
ec = INVALID_ACCESS_ERR;
return String();
}
return element->shadowPseudoId().string();
}
#if ENABLE(INPUT_COLOR)
void Internals::selectColorInColorChooser(Element* element, const String& colorValue)
{
if (!element->hasTagName(HTMLNames::inputTag))
return;
HTMLInputElement* inputElement = element->toInputElement();
if (!inputElement)
return;
inputElement->selectColorInColorChooser(Color(colorValue));
}
#endif
#if ENABLE(INSPECTOR)
void Internals::setInspectorResourcesDataSizeLimits(Document* document, int maximumResourcesContentSize, int maximumSingleResourceContentSize, ExceptionCode& ec)
{
if (!document || !document->page() || !document->page()->inspectorController()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->page()->inspectorController()->setResourcesDataSizeLimitsFromInternals(maximumResourcesContentSize, maximumSingleResourceContentSize);
}
#endif
PassRefPtr<ClientRect> Internals::boundingBox(Element* element, ExceptionCode& ec)
{
if (!element) {
ec = INVALID_ACCESS_ERR;
return ClientRect::create();
}
element->document()->updateLayoutIgnorePendingStylesheets();
RenderObject* renderer = element->renderer();
if (!renderer)
return ClientRect::create();
return ClientRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms());
}
unsigned Internals::markerCountForNode(Node* node, const String& markerType, ExceptionCode& ec)
{
if (!node) {
ec = INVALID_ACCESS_ERR;
return 0;
}
DocumentMarker::MarkerTypes markerTypes = 0;
if (!markerTypesFrom(markerType, markerTypes)) {
ec = SYNTAX_ERR;
return 0;
}
return node->document()->markers()->markersFor(node, markerTypes).size();
}
PassRefPtr<Range> Internals::markerRangeForNode(Node* node, const String& markerType, unsigned index, ExceptionCode& ec)
{
if (!node) {
ec = INVALID_ACCESS_ERR;
return 0;
}
DocumentMarker::MarkerTypes markerTypes = 0;
if (!markerTypesFrom(markerType, markerTypes)) {
ec = SYNTAX_ERR;
return 0;
}
Vector<DocumentMarker*> markers = node->document()->markers()->markersFor(node, markerTypes);
if (markers.size() <= index)
return 0;
return Range::create(node->document(), node, markers[index]->startOffset(), node, markers[index]->endOffset());
}
void Internals::setForceCompositingMode(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->settings()->setForceCompositingMode(enabled);
}
void Internals::setEnableCompositingForFixedPosition(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->settings()->setAcceleratedCompositingForFixedPositionEnabled(enabled);
}
void Internals::setEnableCompositingForScrollableFrames(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->settings()->setAcceleratedCompositingForScrollableFramesEnabled(enabled);
}
void Internals::setAcceleratedDrawingEnabled(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->settings()->setAcceleratedDrawingEnabled(enabled);
}
void Internals::setAcceleratedFiltersEnabled(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->settings()->setAcceleratedFiltersEnabled(enabled);
}
void Internals::setEnableScrollAnimator(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
#if ENABLE(SMOOTH_SCROLLING)
document->settings()->setEnableScrollAnimator(enabled);
#else
UNUSED_PARAM(enabled);
#endif
}
void Internals::setZoomAnimatorTransform(Document *document, float scale, float tx, float ty, ExceptionCode& ec)
{
if (!document || !document->view() || !document->view()->frame()) {
ec = INVALID_ACCESS_ERR;
return;
}
#if ENABLE(GESTURE_EVENTS)
PlatformGestureEvent pge(PlatformGestureEvent::DoubleTapType, IntPoint(tx, ty), IntPoint(tx, ty), 0, scale, 0.f, 0, 0, 0, 0);
document->view()->frame()->eventHandler()->handleGestureEvent(pge);
#else
UNUSED_PARAM(scale);
UNUSED_PARAM(tx);
UNUSED_PARAM(ty);
#endif
}
float Internals::getPageScaleFactor(Document *document, ExceptionCode& ec)
{
if (!document || !document->page()) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return document->page()->pageScaleFactor();
}
void Internals::setZoomParameters(Document* document, float scale, float x, float y, ExceptionCode& ec)
{
if (!document || !document->view() || !document->view()->frame()) {
ec = INVALID_ACCESS_ERR;
return;
}
#if ENABLE(SMOOTH_SCROLLING)
document->view()->scrollAnimator()->setZoomParametersForTest(scale, x, y);
#else
UNUSED_PARAM(scale);
UNUSED_PARAM(x);
UNUSED_PARAM(y);
#endif
}
void Internals::setMockScrollbarsEnabled(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->settings()->setMockScrollbarsEnabled(enabled);
}
void Internals::setPasswordEchoEnabled(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
if (!passwordEchoEnabledBackedUp) {
passwordEchoEnabledBackup = document->settings()->passwordEchoEnabled();
passwordEchoEnabledBackedUp = true;
}
document->settings()->setPasswordEchoEnabled(enabled);
}
void Internals::setPasswordEchoDurationInSeconds(Document* document, double durationInSeconds, ExceptionCode& ec)
{
if (!document || !document->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
if (!passwordEchoDurationInSecondsBackedUp) {
passwordEchoDurationInSecondsBackup = document->settings()->passwordEchoDurationInSeconds();
passwordEchoDurationInSecondsBackedUp = true;
}
document->settings()->setPasswordEchoDurationInSeconds(durationInSeconds);
}
void Internals::setScrollViewPosition(Document* document, long x, long y, ExceptionCode& ec)
{
if (!document || !document->view()) {
ec = INVALID_ACCESS_ERR;
return;
}
FrameView* frameView = document->view();
bool constrainsScrollingToContentEdgeOldValue = frameView->constrainsScrollingToContentEdge();
bool scrollbarsSuppressedOldValue = frameView->scrollbarsSuppressed();
frameView->setConstrainsScrollingToContentEdge(false);
frameView->setScrollbarsSuppressed(false);
frameView->setScrollOffsetFromInternals(IntPoint(x, y));
frameView->setScrollbarsSuppressed(scrollbarsSuppressedOldValue);
frameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue);
}
void Internals::setPagination(Document* document, const String& mode, int gap, ExceptionCode& ec)
{
if (!document || !document->page()) {
ec = INVALID_ACCESS_ERR;
return;
}
Page::Pagination pagination;
if (mode == "Unpaginated")
pagination.mode = Page::Pagination::Unpaginated;
else if (mode == "HorizontallyPaginated")
pagination.mode = Page::Pagination::HorizontallyPaginated;
else if (mode == "VerticallyPaginated")
pagination.mode = Page::Pagination::VerticallyPaginated;
else {
ec = SYNTAX_ERR;
return;
}
pagination.gap = gap;
document->page()->setPagination(pagination);
}
void Internals::reset(Document* document)
{
if (!document || !document->settings())
return;
if (passwordEchoDurationInSecondsBackedUp) {
document->settings()->setPasswordEchoDurationInSeconds(passwordEchoDurationInSecondsBackup);
passwordEchoDurationInSecondsBackedUp = false;
}
if (passwordEchoEnabledBackedUp) {
document->settings()->setPasswordEchoEnabled(passwordEchoEnabledBackup);
passwordEchoEnabledBackedUp = false;
}
if (Page* page = document->page())
page->setPagination(Page::Pagination());
}
bool Internals::wasLastChangeUserEdit(Element* textField, ExceptionCode& ec)
{
if (!textField) {
ec = INVALID_ACCESS_ERR;
return false;
}
if (HTMLInputElement* inputElement = textField->toInputElement())
return inputElement->lastChangeWasUserEdit();
// FIXME: We should be using hasTagName instead but Windows port doesn't link QualifiedNames properly.
if (textField->tagName() == "TEXTAREA")
return static_cast<HTMLTextAreaElement*>(textField)->lastChangeWasUserEdit();
ec = INVALID_NODE_TYPE_ERR;
return false;
}
String Internals::suggestedValue(Element* element, ExceptionCode& ec)
{
if (!element) {
ec = INVALID_ACCESS_ERR;
return String();
}
HTMLInputElement* inputElement = element->toInputElement();
if (!inputElement) {
ec = INVALID_NODE_TYPE_ERR;
return String();
}
return inputElement->suggestedValue();
}
void Internals::setSuggestedValue(Element* element, const String& value, ExceptionCode& ec)
{
if (!element) {
ec = INVALID_ACCESS_ERR;
return;
}
HTMLInputElement* inputElement = element->toInputElement();
if (!inputElement) {
ec = INVALID_NODE_TYPE_ERR;
return;
}
inputElement->setSuggestedValue(value);
}
void Internals::scrollElementToRect(Element* element, long x, long y, long w, long h, ExceptionCode& ec)
{
if (!element || !element->document() || !element->document()->view()) {
ec = INVALID_ACCESS_ERR;
return;
}
FrameView* frameView = element->document()->view();
frameView->scrollElementToRect(element, IntRect(x, y, w, h));
}
void Internals::paintControlTints(Document* document, ExceptionCode& ec)
{
if (!document || !document->view()) {
ec = INVALID_ACCESS_ERR;
return;
}
FrameView* frameView = document->view();
frameView->paintControlTints();
}
PassRefPtr<Range> Internals::rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, ExceptionCode& ec)
{
if (!scope) {
ec = INVALID_ACCESS_ERR;
return 0;
}
return TextIterator::rangeFromLocationAndLength(scope, rangeLocation, rangeLength);
}
unsigned Internals::locationFromRange(Element* scope, const Range* range, ExceptionCode& ec)
{
if (!scope || !range) {
ec = INVALID_ACCESS_ERR;
return 0;
}
size_t location = 0;
size_t unusedLength = 0;
TextIterator::getLocationAndLengthFromRange(scope, range, location, unusedLength);
return location;
}
unsigned Internals::lengthFromRange(Element* scope, const Range* range, ExceptionCode& ec)
{
if (!scope || !range) {
ec = INVALID_ACCESS_ERR;
return 0;
}
size_t unusedLocation = 0;
size_t length = 0;
TextIterator::getLocationAndLengthFromRange(scope, range, unusedLocation, length);
return length;
}
void Internals::setShouldLayoutFixedElementsRelativeToFrame(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->view()) {
ec = INVALID_ACCESS_ERR;
return;
}
FrameView* frameView = document->view();
frameView->setShouldLayoutFixedElementsRelativeToFrame(enabled);
}
void Internals::setUnifiedTextCheckingEnabled(Document* document, bool enabled, ExceptionCode& ec)
{
if (!document || !document->frame() || !document->frame()->settings()) {
ec = INVALID_ACCESS_ERR;
return;
}
document->frame()->settings()->setUnifiedTextCheckerEnabled(enabled);
}
bool Internals::unifiedTextCheckingEnabled(Document* document, ExceptionCode& ec)
{
if (!document || !document->frame() || !document->frame()->settings()) {
ec = INVALID_ACCESS_ERR;
return false;
}
return document->frame()->settings()->unifiedTextCheckerEnabled();
}
int Internals::lastSpellCheckRequestSequence(Document* document, ExceptionCode& ec)
{
SpellChecker* checker = spellchecker(document);
if (!checker) {
ec = INVALID_ACCESS_ERR;
return -1;
}
return checker->lastRequestSequence();
}
int Internals::lastSpellCheckProcessedSequence(Document* document, ExceptionCode& ec)
{
SpellChecker* checker = spellchecker(document);
if (!checker) {
ec = INVALID_ACCESS_ERR;
return -1;
}
return checker->lastProcessedSequence();
}
}