When page scaling is in use position:fixed has incorrect results
[WebKit-https.git] / Source / WebCore / testing / Internals.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Internals.h"
28
29 #include "CachedResourceLoader.h"
30 #include "ClientRect.h"
31 #include "Document.h"
32 #include "DocumentMarker.h"
33 #include "DocumentMarkerController.h"
34 #include "Element.h"
35 #include "ExceptionCode.h"
36 #include "Frame.h"
37 #include "FrameView.h"
38 #include "HTMLInputElement.h"
39 #include "HTMLNames.h"
40 #include "HTMLTextAreaElement.h"
41 #include "InspectorController.h"
42 #include "IntRect.h"
43 #include "NodeRenderingContext.h"
44 #include "Page.h"
45 #include "Range.h"
46 #include "RenderObject.h"
47 #include "RenderTreeAsText.h"
48 #include "Settings.h"
49 #include "ShadowContentElement.h"
50 #include "ShadowRoot.h"
51 #include "TextIterator.h"
52
53 #if ENABLE(GESTURE_EVENTS)
54 #include "PlatformGestureEvent.h"
55 #endif
56
57 #if ENABLE(SMOOTH_SCROLLING)
58 #include "ScrollAnimator.h"
59 #endif
60
61 #if ENABLE(INPUT_COLOR)
62 #include "ColorChooser.h"
63 #endif
64
65 namespace WebCore {
66
67 static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result)
68 {
69     if (markerType.isEmpty() || equalIgnoringCase(markerType, "all"))
70         result = DocumentMarker::AllMarkers();
71     else if (equalIgnoringCase(markerType, "Spelling"))
72         result =  DocumentMarker::Spelling;
73     else if (equalIgnoringCase(markerType, "Grammar"))
74         result =  DocumentMarker::Grammar;
75     else if (equalIgnoringCase(markerType, "TextMatch"))
76         result =  DocumentMarker::TextMatch;
77     else if (equalIgnoringCase(markerType, "Replacement"))
78         result =  DocumentMarker::Replacement;
79     else if (equalIgnoringCase(markerType, "CorrectionIndicator"))
80         result =  DocumentMarker::CorrectionIndicator;
81     else if (equalIgnoringCase(markerType, "RejectedCorrection"))
82         result =  DocumentMarker::RejectedCorrection;
83     else if (equalIgnoringCase(markerType, "Autocorrected"))
84         result =  DocumentMarker::Autocorrected;
85     else if (equalIgnoringCase(markerType, "SpellCheckingExemption"))
86         result =  DocumentMarker::SpellCheckingExemption;
87     else if (equalIgnoringCase(markerType, "DeletedAutocorrection"))
88         result =  DocumentMarker::DeletedAutocorrection;
89     else
90         return false;
91
92     return true;
93 }
94
95 const char* Internals::internalsId = "internals";
96
97 PassRefPtr<Internals> Internals::create()
98 {
99     return adoptRef(new Internals);
100 }
101
102 Internals::~Internals()
103 {
104 }
105
106 Internals::Internals()
107     : passwordEchoDurationInSecondsBackedUp(false)
108     , passwordEchoEnabledBackedUp(false)
109 {
110 }
111
112 bool Internals::isPreloaded(Document* document, const String& url)
113 {
114     if (!document)
115         return false;
116
117     return document->cachedResourceLoader()->isPreloaded(url);
118 }
119
120 PassRefPtr<Element> Internals::createShadowContentElement(Document* document, ExceptionCode& ec)
121 {
122     if (!document) {
123         ec = INVALID_ACCESS_ERR;
124         return 0;
125     }
126
127     return ShadowContentElement::create(document);
128 }
129
130 Element* Internals::getElementByIdInShadowRoot(Node* shadowRoot, const String& id, ExceptionCode& ec)
131 {
132     if (!shadowRoot || !shadowRoot->isShadowRoot()) {
133         ec = INVALID_ACCESS_ERR;
134         return 0;
135     }
136     return toShadowRoot(shadowRoot)->getElementById(id);
137 }
138
139 String Internals::elementRenderTreeAsText(Element* element, ExceptionCode& ec)
140 {
141     if (!element) {
142         ec = INVALID_ACCESS_ERR;
143         return String();
144     }
145
146     String representation = externalRepresentation(element);
147     if (representation.isEmpty()) {
148         ec = INVALID_ACCESS_ERR;
149         return String();
150     }
151
152     return representation;
153 }
154
155 Node* Internals::ensureShadowRoot(Element* host, ExceptionCode& ec)
156 {
157     if (!host) {
158         ec = INVALID_ACCESS_ERR;
159         return 0;
160     }
161
162     return host->ensureShadowRoot();
163 }
164
165 Node* Internals::shadowRoot(Element* host, ExceptionCode& ec)
166 {
167     if (!host) {
168         ec = INVALID_ACCESS_ERR;
169         return 0;
170     }
171
172     return host->shadowRoot();
173 }
174
175 void Internals::removeShadowRoot(Element* host, ExceptionCode& ec)
176 {
177     if (!host) {
178         ec = INVALID_ACCESS_ERR;
179         return;
180     }
181
182     host->removeShadowRoot();
183 }
184
185 Element* Internals::includerFor(Node* node, ExceptionCode& ec)
186 {
187     if (!node) {
188         ec = INVALID_ACCESS_ERR;
189         return 0;
190     }
191
192     return NodeRenderingContext(node).includer();
193 }
194
195 String Internals::shadowPseudoId(Element* element, ExceptionCode& ec)
196 {
197     if (!element) {
198         ec = INVALID_ACCESS_ERR;
199         return String();
200     }
201
202     return element->shadowPseudoId().string();
203 }
204
205 #if ENABLE(INPUT_COLOR)
206 void Internals::selectColorInColorChooser(Element* element, const String& colorValue)
207 {
208     if (!element->hasTagName(HTMLNames::inputTag))
209         return;
210     HTMLInputElement* inputElement = element->toInputElement();
211     if (!inputElement)
212         return;
213     inputElement->selectColorInColorChooser(Color(colorValue));
214 }
215 #endif
216
217 #if ENABLE(INSPECTOR)
218 void Internals::setInspectorResourcesDataSizeLimits(Document* document, int maximumResourcesContentSize, int maximumSingleResourceContentSize, ExceptionCode& ec)
219 {
220     if (!document || !document->page() || !document->page()->inspectorController()) {
221         ec = INVALID_ACCESS_ERR;
222         return;
223     }
224     document->page()->inspectorController()->setResourcesDataSizeLimitsFromInternals(maximumResourcesContentSize, maximumSingleResourceContentSize);
225 }
226 #endif
227
228 PassRefPtr<ClientRect> Internals::boundingBox(Element* element, ExceptionCode& ec)
229 {
230     if (!element) {
231         ec = INVALID_ACCESS_ERR;
232         return ClientRect::create();
233     }
234
235     element->document()->updateLayoutIgnorePendingStylesheets();
236     RenderObject* renderer = element->renderer();
237     if (!renderer)
238         return ClientRect::create();
239     return ClientRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms());
240 }
241
242 unsigned Internals::markerCountForNode(Node* node, const String& markerType, ExceptionCode& ec)
243 {
244     if (!node) {
245         ec = INVALID_ACCESS_ERR;
246         return 0;
247     }
248
249     DocumentMarker::MarkerTypes markerTypes = 0;
250     if (!markerTypesFrom(markerType, markerTypes)) {
251         ec = SYNTAX_ERR;
252         return 0;
253     }
254
255     return node->document()->markers()->markersFor(node, markerTypes).size();
256 }
257
258 PassRefPtr<Range> Internals::markerRangeForNode(Node* node, const String& markerType, unsigned index, ExceptionCode& ec)
259 {
260     if (!node) {
261         ec = INVALID_ACCESS_ERR;
262         return 0;
263     }
264
265     DocumentMarker::MarkerTypes markerTypes = 0;
266     if (!markerTypesFrom(markerType, markerTypes)) {
267         ec = SYNTAX_ERR;
268         return 0;
269     }
270
271     Vector<DocumentMarker*> markers = node->document()->markers()->markersFor(node, markerTypes);
272     if (markers.size() <= index)
273         return 0;
274     return Range::create(node->document(), node, markers[index]->startOffset(), node, markers[index]->endOffset());
275 }
276
277 void Internals::setForceCompositingMode(Document* document, bool enabled, ExceptionCode& ec)
278 {
279     if (!document || !document->settings()) {
280         ec = INVALID_ACCESS_ERR;
281         return;
282     }
283
284     document->settings()->setForceCompositingMode(enabled);
285 }
286
287 void Internals::setEnableCompositingForFixedPosition(Document* document, bool enabled, ExceptionCode& ec)
288 {
289     if (!document || !document->settings()) {
290         ec = INVALID_ACCESS_ERR;
291         return;
292     }
293
294     document->settings()->setAcceleratedCompositingForFixedPositionEnabled(enabled);
295 }
296
297 void Internals::setEnableCompositingForScrollableFrames(Document* document, bool enabled, ExceptionCode& ec)
298 {
299     if (!document || !document->settings()) {
300         ec = INVALID_ACCESS_ERR;
301         return;
302     }
303
304     document->settings()->setAcceleratedCompositingForScrollableFramesEnabled(enabled);
305 }
306
307 void Internals::setAcceleratedDrawingEnabled(Document* document, bool enabled, ExceptionCode& ec)
308 {
309     if (!document || !document->settings()) {
310         ec = INVALID_ACCESS_ERR;
311         return;
312     }
313
314     document->settings()->setAcceleratedDrawingEnabled(enabled);
315 }
316
317 void Internals::setEnableScrollAnimator(Document* document, bool enabled, ExceptionCode& ec)
318 {
319     if (!document || !document->settings()) {
320         ec = INVALID_ACCESS_ERR;
321         return;
322     }
323
324 #if ENABLE(SMOOTH_SCROLLING)
325     document->settings()->setEnableScrollAnimator(enabled);
326 #else
327     UNUSED_PARAM(enabled);
328 #endif
329 }
330
331 void Internals::setZoomAnimatorTransform(Document *document, float scale, float tx, float ty, ExceptionCode& ec)
332 {
333     if (!document || !document->view() || !document->view()->frame()) {
334         ec = INVALID_ACCESS_ERR;
335         return;
336     }
337
338 #if ENABLE(GESTURE_EVENTS)
339     PlatformGestureEvent pge(PlatformGestureEvent::DoubleTapType, IntPoint(tx, ty), IntPoint(tx, ty), 0, scale, 0.f, 0, 0, 0, 0);
340     document->view()->frame()->eventHandler()->handleGestureEvent(pge);
341 #else
342     UNUSED_PARAM(scale);
343     UNUSED_PARAM(tx);
344     UNUSED_PARAM(ty);
345 #endif
346 }
347
348 float Internals::getPageScaleFactor(Document *document, ExceptionCode& ec)
349 {
350     if (!document || !document->page()) {
351         ec = INVALID_ACCESS_ERR;
352         return 0;
353     }
354
355     return document->page()->pageScaleFactor();
356 }
357
358 void Internals::setZoomParameters(Document* document, float scale, float x, float y, ExceptionCode& ec)
359 {
360     if (!document || !document->view() || !document->view()->frame()) {
361         ec = INVALID_ACCESS_ERR;
362         return;
363     }
364
365 #if ENABLE(SMOOTH_SCROLLING)
366     document->view()->scrollAnimator()->setZoomParametersForTest(scale, x, y);
367 #else
368     UNUSED_PARAM(scale);
369     UNUSED_PARAM(x);
370     UNUSED_PARAM(y);
371 #endif
372 }
373
374 void Internals::setMockScrollbarsEnabled(Document* document, bool enabled, ExceptionCode& ec)
375 {
376     if (!document || !document->settings()) {
377         ec = INVALID_ACCESS_ERR;
378         return;
379     }
380
381     document->settings()->setMockScrollbarsEnabled(enabled);
382 }
383
384 void Internals::setPasswordEchoEnabled(Document* document, bool enabled, ExceptionCode& ec)
385 {
386     if (!document || !document->settings()) {
387         ec = INVALID_ACCESS_ERR;
388         return;
389     }
390
391     if (!passwordEchoEnabledBackedUp) {
392         passwordEchoEnabledBackup = document->settings()->passwordEchoEnabled();
393         passwordEchoEnabledBackedUp = true;
394     }
395     document->settings()->setPasswordEchoEnabled(enabled);
396 }
397
398 void Internals::setPasswordEchoDurationInSeconds(Document* document, double durationInSeconds, ExceptionCode& ec)
399 {
400     if (!document || !document->settings()) {
401         ec = INVALID_ACCESS_ERR;
402         return;
403     }
404
405     if (!passwordEchoDurationInSecondsBackedUp) {
406         passwordEchoDurationInSecondsBackup = document->settings()->passwordEchoDurationInSeconds();
407         passwordEchoDurationInSecondsBackedUp = true;
408     }
409     document->settings()->setPasswordEchoDurationInSeconds(durationInSeconds);
410 }
411
412 void Internals::setScrollViewPosition(Document* document, long x, long y, ExceptionCode& ec)
413 {
414     if (!document || !document->view()) {
415         ec = INVALID_ACCESS_ERR;
416         return;
417     }
418
419     FrameView* frameView = document->view();
420     bool constrainsScrollingToContentEdgeOldValue = frameView->constrainsScrollingToContentEdge();
421     bool scrollbarsSuppressedOldValue = frameView->scrollbarsSuppressed();
422
423     frameView->setConstrainsScrollingToContentEdge(false);
424     frameView->setScrollbarsSuppressed(false);
425     frameView->setScrollOffsetFromInternals(IntPoint(x, y));
426     frameView->setScrollbarsSuppressed(scrollbarsSuppressedOldValue);
427     frameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue);
428 }
429
430 void Internals::setPagination(Document* document, const String& mode, int gap, ExceptionCode& ec)
431 {
432     if (!document || !document->page()) {
433         ec = INVALID_ACCESS_ERR;
434         return;
435     }
436
437     Page::Pagination pagination;
438     if (mode == "Unpaginated")
439         pagination.mode = Page::Pagination::Unpaginated;
440     else if (mode == "HorizontallyPaginated")
441         pagination.mode = Page::Pagination::HorizontallyPaginated;
442     else if (mode == "VerticallyPaginated")
443         pagination.mode = Page::Pagination::VerticallyPaginated;
444     else {
445         ec = SYNTAX_ERR;
446         return;
447     }
448
449     pagination.gap = gap;
450
451     document->page()->setPagination(pagination);
452 }
453
454 void Internals::reset(Document* document)
455 {
456     if (!document || !document->settings())
457         return;
458
459     if (passwordEchoDurationInSecondsBackedUp) {
460         document->settings()->setPasswordEchoDurationInSeconds(passwordEchoDurationInSecondsBackup);
461         passwordEchoDurationInSecondsBackedUp = false;
462     }
463
464     if (passwordEchoEnabledBackedUp) {
465         document->settings()->setPasswordEchoEnabled(passwordEchoEnabledBackup);
466         passwordEchoEnabledBackedUp = false;
467     }
468
469     if (Page* page = document->page())
470         page->setPagination(Page::Pagination());
471 }
472
473 bool Internals::wasLastChangeUserEdit(Element* textField, ExceptionCode& ec)
474 {
475     if (!textField) {
476         ec = INVALID_ACCESS_ERR;
477         return false;
478     }
479
480     if (HTMLInputElement* inputElement = textField->toInputElement())
481         return inputElement->lastChangeWasUserEdit();
482
483     // FIXME: We should be using hasTagName instead but Windows port doesn't link QualifiedNames properly.
484     if (textField->tagName() == "TEXTAREA")
485         return static_cast<HTMLTextAreaElement*>(textField)->lastChangeWasUserEdit();
486
487     ec = INVALID_NODE_TYPE_ERR;
488     return false;
489 }
490
491 String Internals::suggestedValue(Element* element, ExceptionCode& ec)
492 {
493     if (!element) {
494         ec = INVALID_ACCESS_ERR;
495         return String();
496     }
497
498     HTMLInputElement* inputElement = element->toInputElement();
499     if (!inputElement) {
500         ec = INVALID_NODE_TYPE_ERR;
501         return String();
502     }
503
504     return inputElement->suggestedValue();
505 }
506
507 void Internals::setSuggestedValue(Element* element, const String& value, ExceptionCode& ec)
508 {
509     if (!element) {
510         ec = INVALID_ACCESS_ERR;
511         return;
512     }
513
514     HTMLInputElement* inputElement = element->toInputElement();
515     if (!inputElement) {
516         ec = INVALID_NODE_TYPE_ERR;
517         return;
518     }
519
520     inputElement->setSuggestedValue(value);
521 }
522
523 void Internals::scrollElementToRect(Element* element, long x, long y, long w, long h, ExceptionCode& ec)
524 {
525     if (!element || !element->document() || !element->document()->view()) {
526         ec = INVALID_ACCESS_ERR;
527         return;
528     }
529     FrameView* frameView = element->document()->view();
530     frameView->scrollElementToRect(element, IntRect(x, y, w, h));
531 }
532
533 void Internals::paintControlTints(Document* document, ExceptionCode& ec)
534 {
535     if (!document || !document->view()) {
536         ec = INVALID_ACCESS_ERR;
537         return;
538     }
539
540     FrameView* frameView = document->view();
541     frameView->paintControlTints();
542 }
543
544 PassRefPtr<Range> Internals::rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, ExceptionCode& ec)
545 {
546     if (!scope) {
547         ec = INVALID_ACCESS_ERR;
548         return 0;
549     }
550
551     return TextIterator::rangeFromLocationAndLength(scope, rangeLocation, rangeLength);
552 }
553
554 unsigned Internals::locationFromRange(Element* scope, const Range* range, ExceptionCode& ec)
555 {
556     if (!scope || !range) {
557         ec = INVALID_ACCESS_ERR;
558         return 0;
559     }
560
561     size_t location = 0;
562     size_t unusedLength = 0;
563     TextIterator::getLocationAndLengthFromRange(scope, range, location, unusedLength);
564     return location;
565 }
566
567 unsigned Internals::lengthFromRange(Element* scope, const Range* range, ExceptionCode& ec)
568 {
569     if (!scope || !range) {
570         ec = INVALID_ACCESS_ERR;
571         return 0;
572     }
573
574     size_t unusedLocation = 0;
575     size_t length = 0;
576     TextIterator::getLocationAndLengthFromRange(scope, range, unusedLocation, length);
577     return length;
578 }
579
580 void Internals::setShouldLayoutFixedElementsRelativeToFrame(Document* document, bool enabled, ExceptionCode& ec)
581 {
582     if (!document || !document->view()) {
583         ec = INVALID_ACCESS_ERR;
584         return;
585     }
586
587     FrameView* frameView = document->view();
588     frameView->setShouldLayoutFixedElementsRelativeToFrame(enabled);
589 }
590
591 void Internals::setUnifiedTextCheckingEnabled(Document* document, bool enabled, ExceptionCode& ec)
592 {
593     if (!document || !document->frame() || !document->frame()->settings()) {
594         ec = INVALID_ACCESS_ERR;
595         return;
596     }
597
598     document->frame()->settings()->setUnifiedTextCheckerEnabled(enabled);
599 }
600
601 bool Internals::unifiedTextCheckingEnabled(Document* document, ExceptionCode& ec)
602 {
603     if (!document || !document->frame() || !document->frame()->settings()) {
604         ec = INVALID_ACCESS_ERR;
605         return false;
606     }
607
608     return document->frame()->settings()->unifiedTextCheckerEnabled();
609 }
610
611 }