0ffa19789061649703beb45ed6cc740e7cefa98f
[WebKit-https.git] / Source / WebKit / mac / DOM / DOM.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 James G. Speth (speth@end.com)
4  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #import "DOM.h"
29
30 #import "ExceptionHandlers.h"
31 #import "DOMElementInternal.h"
32 #import "DOMHTMLCanvasElement.h"
33 #import "DOMHTMLTableCellElementInternal.h"
34 #import "DOMHTMLVideoElement.h"
35 #import "DOMInternal.h"
36 #import "DOMNodeInternal.h"
37 #import "DOMPrivate.h"
38 #import "DOMRangeInternal.h"
39 #import <JavaScriptCore/APICast.h>
40 #import <WebCore/CachedImage.h>
41 #import <WebCore/DragImage.h>
42 #import <WebCore/FocusController.h>
43 #import <WebCore/FontCascade.h>
44 #import <WebCore/Frame.h>
45 #import <WebCore/HTMLLinkElement.h>
46 #import <WebCore/HTMLNames.h>
47 #import <WebCore/HTMLParserIdioms.h>
48 #import <WebCore/HTMLTableCellElement.h>
49 #import <WebCore/Image.h>
50 #import <WebCore/JSNode.h>
51 #import <WebCore/KeyboardEvent.h>
52 #import <WebCore/MediaList.h>
53 #import <WebCore/MediaQueryEvaluator.h>
54 #import <WebCore/NodeFilter.h>
55 #import <WebCore/NodeRenderStyle.h>
56 #import <WebCore/Page.h>
57 #import <WebCore/Range.h>
58 #import <WebCore/RenderImage.h>
59 #import <WebCore/RenderView.h>
60 #import <WebCore/ScriptController.h>
61 #import <WebCore/TextIndicator.h>
62 #import <WebCore/Touch.h>
63 #import <WebCore/WebScriptObjectPrivate.h>
64 #import <wtf/HashMap.h>
65
66 #if PLATFORM(IOS)
67 #import <WebCore/WAKAppKitStubs.h>
68 #import <WebCore/WAKWindow.h>
69 #import <WebCore/WebCoreThreadMessage.h>
70 #endif
71
72 using namespace JSC;
73 using namespace WebCore;
74
75 // FIXME: These methods should move into the implementation files of the DOM classes
76 // and this file should be eliminated.
77
78 //------------------------------------------------------------------------------------------
79 // DOMNode
80
81 typedef HashMap<const QualifiedName::QualifiedNameImpl*, Class> ObjCClassMap;
82 static ObjCClassMap* elementClassMap;
83
84 static void addElementClass(const QualifiedName& tag, Class objCClass)
85 {
86     elementClassMap->set(tag.impl(), objCClass);
87 }
88
89 static void createElementClassMap()
90 {
91     // Create the table.
92     elementClassMap = new ObjCClassMap;
93
94     addElementClass(HTMLNames::aTag, [DOMHTMLAnchorElement class]);
95     addElementClass(HTMLNames::appletTag, [DOMHTMLAppletElement class]);
96     addElementClass(HTMLNames::areaTag, [DOMHTMLAreaElement class]);
97     addElementClass(HTMLNames::baseTag, [DOMHTMLBaseElement class]);
98     addElementClass(HTMLNames::basefontTag, [DOMHTMLBaseFontElement class]);
99     addElementClass(HTMLNames::bodyTag, [DOMHTMLBodyElement class]);
100     addElementClass(HTMLNames::brTag, [DOMHTMLBRElement class]);
101     addElementClass(HTMLNames::buttonTag, [DOMHTMLButtonElement class]);
102     addElementClass(HTMLNames::canvasTag, [DOMHTMLCanvasElement class]);
103     addElementClass(HTMLNames::captionTag, [DOMHTMLTableCaptionElement class]);
104     addElementClass(HTMLNames::colTag, [DOMHTMLTableColElement class]);
105     addElementClass(HTMLNames::colgroupTag, [DOMHTMLTableColElement class]);
106     addElementClass(HTMLNames::delTag, [DOMHTMLModElement class]);
107     addElementClass(HTMLNames::dirTag, [DOMHTMLDirectoryElement class]);
108     addElementClass(HTMLNames::divTag, [DOMHTMLDivElement class]);
109     addElementClass(HTMLNames::dlTag, [DOMHTMLDListElement class]);
110     addElementClass(HTMLNames::embedTag, [DOMHTMLEmbedElement class]);
111     addElementClass(HTMLNames::fieldsetTag, [DOMHTMLFieldSetElement class]);
112     addElementClass(HTMLNames::fontTag, [DOMHTMLFontElement class]);
113     addElementClass(HTMLNames::formTag, [DOMHTMLFormElement class]);
114     addElementClass(HTMLNames::frameTag, [DOMHTMLFrameElement class]);
115     addElementClass(HTMLNames::framesetTag, [DOMHTMLFrameSetElement class]);
116     addElementClass(HTMLNames::h1Tag, [DOMHTMLHeadingElement class]);
117     addElementClass(HTMLNames::h2Tag, [DOMHTMLHeadingElement class]);
118     addElementClass(HTMLNames::h3Tag, [DOMHTMLHeadingElement class]);
119     addElementClass(HTMLNames::h4Tag, [DOMHTMLHeadingElement class]);
120     addElementClass(HTMLNames::h5Tag, [DOMHTMLHeadingElement class]);
121     addElementClass(HTMLNames::h6Tag, [DOMHTMLHeadingElement class]);
122     addElementClass(HTMLNames::headTag, [DOMHTMLHeadElement class]);
123     addElementClass(HTMLNames::hrTag, [DOMHTMLHRElement class]);
124     addElementClass(HTMLNames::htmlTag, [DOMHTMLHtmlElement class]);
125     addElementClass(HTMLNames::iframeTag, [DOMHTMLIFrameElement class]);
126     addElementClass(HTMLNames::imgTag, [DOMHTMLImageElement class]);
127     addElementClass(HTMLNames::inputTag, [DOMHTMLInputElement class]);
128     addElementClass(HTMLNames::insTag, [DOMHTMLModElement class]);
129     addElementClass(HTMLNames::labelTag, [DOMHTMLLabelElement class]);
130     addElementClass(HTMLNames::legendTag, [DOMHTMLLegendElement class]);
131     addElementClass(HTMLNames::liTag, [DOMHTMLLIElement class]);
132     addElementClass(HTMLNames::linkTag, [DOMHTMLLinkElement class]);
133     addElementClass(HTMLNames::listingTag, [DOMHTMLPreElement class]);
134     addElementClass(HTMLNames::mapTag, [DOMHTMLMapElement class]);
135     addElementClass(HTMLNames::marqueeTag, [DOMHTMLMarqueeElement class]);
136     addElementClass(HTMLNames::menuTag, [DOMHTMLMenuElement class]);
137     addElementClass(HTMLNames::metaTag, [DOMHTMLMetaElement class]);
138     addElementClass(HTMLNames::objectTag, [DOMHTMLObjectElement class]);
139     addElementClass(HTMLNames::olTag, [DOMHTMLOListElement class]);
140     addElementClass(HTMLNames::optgroupTag, [DOMHTMLOptGroupElement class]);
141     addElementClass(HTMLNames::optionTag, [DOMHTMLOptionElement class]);
142     addElementClass(HTMLNames::pTag, [DOMHTMLParagraphElement class]);
143     addElementClass(HTMLNames::paramTag, [DOMHTMLParamElement class]);
144     addElementClass(HTMLNames::preTag, [DOMHTMLPreElement class]);
145     addElementClass(HTMLNames::qTag, [DOMHTMLQuoteElement class]);
146     addElementClass(HTMLNames::scriptTag, [DOMHTMLScriptElement class]);
147     addElementClass(HTMLNames::selectTag, [DOMHTMLSelectElement class]);
148     addElementClass(HTMLNames::styleTag, [DOMHTMLStyleElement class]);
149     addElementClass(HTMLNames::tableTag, [DOMHTMLTableElement class]);
150     addElementClass(HTMLNames::tbodyTag, [DOMHTMLTableSectionElement class]);
151     addElementClass(HTMLNames::tdTag, [DOMHTMLTableCellElement class]);
152     addElementClass(HTMLNames::textareaTag, [DOMHTMLTextAreaElement class]);
153     addElementClass(HTMLNames::tfootTag, [DOMHTMLTableSectionElement class]);
154     addElementClass(HTMLNames::thTag, [DOMHTMLTableCellElement class]);
155     addElementClass(HTMLNames::theadTag, [DOMHTMLTableSectionElement class]);
156     addElementClass(HTMLNames::titleTag, [DOMHTMLTitleElement class]);
157     addElementClass(HTMLNames::trTag, [DOMHTMLTableRowElement class]);
158     addElementClass(HTMLNames::ulTag, [DOMHTMLUListElement class]);
159     addElementClass(HTMLNames::videoTag, [DOMHTMLVideoElement class]);
160     addElementClass(HTMLNames::xmpTag, [DOMHTMLPreElement class]);
161 }
162
163 static Class lookupElementClass(const QualifiedName& tag)
164 {
165     // Do a special lookup to ignore element prefixes
166     if (tag.hasPrefix())
167         return elementClassMap->get(QualifiedName(nullAtom, tag.localName(), tag.namespaceURI()).impl());
168     
169     return elementClassMap->get(tag.impl());
170 }
171
172 static Class elementClass(const QualifiedName& tag, Class defaultClass)
173 {
174     if (!elementClassMap)
175         createElementClassMap();
176     Class objcClass = lookupElementClass(tag);
177     if (!objcClass)
178         objcClass = defaultClass;
179     return objcClass;
180 }
181
182 static NSArray *kit(const Vector<IntRect>& rects)
183 {
184     size_t size = rects.size();
185     NSMutableArray *array = [NSMutableArray arrayWithCapacity:size];
186     for (size_t i = 0; i < size; ++i)
187         [array addObject:[NSValue valueWithRect:rects[i]]];
188     return array;
189 }
190
191 #if PLATFORM(IOS)
192
193 static WKQuad wkQuadFromFloatQuad(const FloatQuad& inQuad)
194 {
195     return { inQuad.p1(), inQuad.p2(), inQuad.p3(), inQuad.p4() };
196 }
197
198 static NSArray *kit(const Vector<FloatQuad>& quads)
199 {
200     NSMutableArray *array = [NSMutableArray arrayWithCapacity:quads.size()];
201     for (auto& quad : quads) {
202         WKQuadObject *quadObject = [[WKQuadObject alloc] initWithQuad:wkQuadFromFloatQuad(quad)];
203         [array addObject:quadObject];
204         [quadObject release];
205     }
206     return array;
207 }
208
209 static inline WKQuad zeroQuad()
210 {
211     return { CGPointZero, CGPointZero, CGPointZero, CGPointZero };
212 }
213
214 @implementation WKQuadObject {
215     WKQuad _quad;
216 }
217
218 - (id)initWithQuad:(WKQuad)quad
219 {
220     if ((self = [super init]))
221         _quad = quad;
222     return self;
223 }
224
225 - (WKQuad)quad
226 {
227     return _quad;
228 }
229
230 - (CGRect)boundingBox
231 {
232     float left = std::min({ _quad.p1.x, _quad.p2.x, _quad.p3.x, _quad.p4.x });
233     float top = std::min({ _quad.p1.y, _quad.p2.y, _quad.p3.y, _quad.p4.y });
234     
235     float right = std::max({ _quad.p1.x, _quad.p2.x, _quad.p3.x, _quad.p4.x });
236     float bottom = std::max({ _quad.p1.y, _quad.p2.y, _quad.p3.y, _quad.p4.y });
237
238     return CGRectMake(left, top, right - left, bottom - top);
239 }
240
241 @end
242
243 #endif
244
245 @implementation DOMNode (WebCoreInternal)
246
247 #pragma clang diagnostic push
248 #pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
249
250 - (NSString *)description
251 {
252     if (!_internal)
253         return [NSString stringWithFormat:@"<%@: null>", [[self class] description]];
254
255     NSString *value = [self nodeValue];
256     if (value)
257         return [NSString stringWithFormat:@"<%@ [%@]: %p '%@'>", [[self class] description], [self nodeName], _internal, value];
258
259     return [NSString stringWithFormat:@"<%@ [%@]: %p>", [[self class] description], [self nodeName], _internal];
260 }
261
262 #pragma clang diagnostic pop
263
264 - (Bindings::RootObject*)_rootObject
265 {
266     auto* frame = core(self)->document().frame();
267     if (!frame)
268         return nullptr;
269     return frame->script().bindingRootObject();
270 }
271
272 @end
273
274 Class kitClass(Node* impl)
275 {
276     switch (impl->nodeType()) {
277         case Node::ELEMENT_NODE:
278             if (is<HTMLElement>(*impl))
279                 return elementClass(downcast<HTMLElement>(*impl).tagQName(), [DOMHTMLElement class]);
280             return [DOMElement class];
281         case Node::ATTRIBUTE_NODE:
282             return [DOMAttr class];
283         case Node::TEXT_NODE:
284             return [DOMText class];
285         case Node::CDATA_SECTION_NODE:
286             return [DOMCDATASection class];
287         case Node::PROCESSING_INSTRUCTION_NODE:
288             return [DOMProcessingInstruction class];
289         case Node::COMMENT_NODE:
290             return [DOMComment class];
291         case Node::DOCUMENT_NODE:
292             if (static_cast<Document*>(impl)->isHTMLDocument())
293                 return [DOMHTMLDocument class];
294             return [DOMDocument class];
295         case Node::DOCUMENT_TYPE_NODE:
296             return [DOMDocumentType class];
297         case Node::DOCUMENT_FRAGMENT_NODE:
298             return [DOMDocumentFragment class];
299     }
300     ASSERT_NOT_REACHED();
301     return nil;
302 }
303
304 id <DOMEventTarget> kit(EventTarget* eventTarget)
305 {
306     if (!eventTarget)
307         return nil;
308
309     if (auto* node = eventTarget->toNode())
310         return kit(node);
311
312     // We don't have an ObjC binding for XMLHttpRequest.
313
314     return nil;
315 }
316
317 @implementation DOMNode (DOMNodeExtensions)
318
319 #if PLATFORM(IOS)
320 - (CGRect)boundingBox
321 #else
322 - (NSRect)boundingBox
323 #endif
324 {
325     auto& node = *core(self);
326     node.document().updateLayoutIgnorePendingStylesheets();
327     auto* renderer = node.renderer();
328     if (!renderer)
329 #if PLATFORM(IOS)
330         return CGRectZero;
331 #else
332         return NSZeroRect;
333 #endif
334     return renderer->absoluteBoundingBoxRect();
335 }
336
337 - (NSArray *)lineBoxRects
338 {
339     return [self textRects];
340 }
341
342 #if PLATFORM(IOS)
343
344 // quad in page coordinates, taking transforms into account. c.f. - (NSRect)boundingBox;
345 - (WKQuad)absoluteQuad
346 {
347     return [self absoluteQuadAndInsideFixedPosition:0];
348 }
349
350 - (WKQuad)absoluteQuadAndInsideFixedPosition:(BOOL *)insideFixed
351 {
352     auto& node = *core(self);
353     node.document().updateLayoutIgnorePendingStylesheets();
354     auto* renderer = node.renderer();
355     if (!renderer) {
356         if (insideFixed)
357             *insideFixed = false;
358         return zeroQuad();
359     }
360
361     Vector<FloatQuad> quads;
362     bool wasFixed = false;
363     renderer->absoluteQuads(quads, &wasFixed);
364     if (insideFixed)
365         *insideFixed = wasFixed;
366
367     if (quads.size() == 0)
368         return zeroQuad();
369
370     if (quads.size() == 1)
371         return wkQuadFromFloatQuad(quads[0]);
372
373     auto boundingRect = quads[0].boundingBox();
374     for (size_t i = 1; i < quads.size(); ++i)
375         boundingRect.unite(quads[i].boundingBox());
376     return wkQuadFromFloatQuad(boundingRect);
377 }
378
379 // this method is like - (CGRect)boundingBox, but it accounts for for transforms
380 - (CGRect)boundingBoxUsingTransforms
381 {
382     auto& node = *core(self);
383     node.document().updateLayoutIgnorePendingStylesheets();
384     auto* renderer = node.renderer();
385     if (!renderer)
386         return CGRectZero;
387     return renderer->absoluteBoundingBoxRect(true);
388 }
389
390 // returns array of WKQuadObject
391 - (NSArray *)lineBoxQuads
392 {
393     auto& node = *core(self);
394     node.document().updateLayoutIgnorePendingStylesheets();
395     WebCore::RenderObject *renderer = node.renderer();
396     if (!renderer)
397         return nil;
398     Vector<WebCore::FloatQuad> quads;
399     renderer->absoluteQuads(quads);
400     return kit(quads);
401 }
402
403 - (Element*)_linkElement
404 {
405     for (auto* node = core(self); node; node = node->parentNode()) {
406         if (node->isLink())
407             return &downcast<Element>(*node);
408     }
409     return nullptr;
410 }
411
412 - (NSURL *)hrefURL
413 {
414     auto* link = [self _linkElement];
415     if (!link)
416         return nil;
417     return link->document().completeURL(stripLeadingAndTrailingHTMLSpaces(link->getAttribute(HTMLNames::hrefAttr)));
418 }
419
420 - (NSString *)hrefTarget
421 {
422     auto* link = [self _linkElement];
423     if (!link)
424         return nil;
425     return link->getAttribute(HTMLNames::targetAttr);
426 }
427
428 - (CGRect)hrefFrame
429 {
430     auto* link = [self _linkElement];
431     if (!link)
432         return CGRectZero;
433     auto* renderer = link->renderer();
434     if (!renderer)
435         return CGRectZero;
436     return renderer->absoluteBoundingBoxRect();
437 }
438
439 - (NSString *)hrefLabel
440 {
441     auto* link = [self _linkElement];
442     if (!link)
443         return nil;
444     return link->textContent();
445 }
446
447 - (NSString *)hrefTitle
448 {
449     auto* link = [self _linkElement];
450     if (!is<HTMLElement>(link))
451         return nil;
452     return link->document().displayStringModifiedByEncoding(downcast<HTMLElement>(*link).title());
453 }
454
455 - (CGRect)boundingFrame
456 {
457     return [self boundingBox];
458 }
459
460 - (WKQuad)innerFrameQuad // takes transforms into account
461 {
462     auto& node = *core(self);
463     node.document().updateLayoutIgnorePendingStylesheets();
464     auto* renderer = node.renderer();
465     if (!renderer)
466         return zeroQuad();
467
468     auto& style = renderer->style();
469     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true /* use transforms*/);
470
471     boundingBox.move(style.borderLeftWidth(), style.borderTopWidth());
472     boundingBox.setWidth(boundingBox.width() - style.borderLeftWidth() - style.borderRightWidth());
473     boundingBox.setHeight(boundingBox.height() - style.borderBottomWidth() - style.borderTopWidth());
474
475     // FIXME: This function advertises returning a quad, but it actually returns a bounding box (so there is no rotation, for instance).
476     return wkQuadFromFloatQuad(FloatQuad(boundingBox));
477 }
478
479 - (float)computedFontSize
480 {
481     auto* style = core(self)->renderStyle();
482     if (!style)
483         return 0.0f;
484     return style->fontDescription().computedSize();
485 }
486
487 - (DOMNode *)nextFocusNode
488 {
489     Page* page = core(self)->document().page();
490     if (!page)
491         return nil;
492     return kit(page->focusController().nextFocusableElement(*core(self)));
493 }
494
495 - (DOMNode *)previousFocusNode
496 {
497     Page* page = core(self)->document().page();
498     if (!page)
499         return nil;
500     return kit(page->focusController().previousFocusableElement(*core(self)));
501 }
502
503 #endif // PLATFORM(IOS)
504
505 @end
506
507 @implementation DOMNode (DOMNodeExtensionsPendingPublic)
508
509 #if PLATFORM(MAC)
510
511 - (NSImage *)renderedImage
512 {
513     auto& node = *core(self);
514     auto* frame = node.document().frame();
515     if (!frame)
516         return nil;
517     return createDragImageForNode(*frame, node).autorelease();
518 }
519
520 #endif
521
522 - (NSArray *)textRects
523 {
524     auto& node = *core(self);
525     node.document().updateLayoutIgnorePendingStylesheets();
526     if (!node.renderer())
527         return nil;
528     Vector<WebCore::IntRect> rects;
529     node.textRects(rects);
530     return kit(rects);
531 }
532
533 @end
534
535 @implementation DOMNode (WebPrivate)
536
537 + (id)_nodeFromJSWrapper:(JSObjectRef)jsWrapper
538 {
539     JSObject* object = toJS(jsWrapper);
540     if (!object->inherits(*object->vm(), JSNode::info()))
541         return nil;
542     return kit(&jsCast<JSNode*>(object)->wrapped());
543 }
544
545 - (void)getPreviewSnapshotImage:(CGImageRef*)cgImage andRects:(NSArray **)rects
546 {
547     if (!cgImage || !rects)
548         return;
549
550     *cgImage = nullptr;
551     *rects = nullptr;
552
553     auto& node = *core(self);
554
555     Ref<Range> range = rangeOfContents(node);
556
557     const float margin = 4 / node.document().page()->pageScaleFactor();
558     RefPtr<TextIndicator> textIndicator = TextIndicator::createWithRange(range, TextIndicatorOptionTightlyFitContent |
559         TextIndicatorOptionRespectTextColor |
560         TextIndicatorOptionPaintBackgrounds |
561         TextIndicatorOptionUseBoundingRectAndPaintAllContentForComplexRanges |
562         TextIndicatorOptionIncludeMarginIfRangeMatchesSelection,
563         TextIndicatorPresentationTransition::None, FloatSize(margin, margin));
564
565     if (textIndicator) {
566         if (Image* image = textIndicator->contentImage())
567             *cgImage = image->nativeImage().autorelease();
568     }
569
570     RetainPtr<NSMutableArray> rectArray = adoptNS([[NSMutableArray alloc] init]);
571
572     if (!*cgImage) {
573         if (auto* renderer = node.renderer()) {
574             FloatRect boundingBox;
575             if (renderer->isRenderImage())
576                 boundingBox = downcast<RenderImage>(*renderer).absoluteContentQuad().enclosingBoundingBox();
577             else
578                 boundingBox = renderer->absoluteBoundingBoxRect();
579
580             boundingBox.inflate(margin);
581
582             CGRect cgRect = node.document().frame()->view()->contentsToWindow(enclosingIntRect(boundingBox));
583             [rectArray addObject:[NSValue value:&cgRect withObjCType:@encode(CGRect)]];
584
585             *rects = rectArray.autorelease();
586         }
587         return;
588     }
589
590     FloatPoint origin = textIndicator->textBoundingRectInRootViewCoordinates().location();
591     for (const FloatRect& rect : textIndicator->textRectsInBoundingRectCoordinates()) {
592         CGRect cgRect = rect;
593         cgRect.origin.x += origin.x();
594         cgRect.origin.y += origin.y();
595         cgRect = node.document().frame()->view()->contentsToWindow(enclosingIntRect(cgRect));
596         [rectArray addObject:[NSValue value:&cgRect withObjCType:@encode(CGRect)]];
597     }
598
599     *rects = rectArray.autorelease();
600 }
601
602 @end
603
604 @implementation DOMRange (DOMRangeExtensions)
605
606 #if PLATFORM(IOS)
607 - (CGRect)boundingBox
608 #else
609 - (NSRect)boundingBox
610 #endif
611 {
612     // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
613     auto& range = *core(self);
614     range.ownerDocument().updateLayoutIgnorePendingStylesheets();
615     return range.absoluteBoundingBox();
616 }
617
618 #if PLATFORM(MAC)
619 - (NSImage *)renderedImageForcingBlackText:(BOOL)forceBlackText
620 #else
621 - (CGImageRef)renderedImageForcingBlackText:(BOOL)forceBlackText
622 #endif
623 {
624     auto& range = *core(self);
625     auto* frame = range.ownerDocument().frame();
626     if (!frame)
627         return nil;
628
629     // iOS uses CGImageRef for drag images, which doesn't support separate logical/physical sizes.
630 #if PLATFORM(MAC)
631     RetainPtr<NSImage> renderedImage = createDragImageForRange(*frame, range, forceBlackText);
632
633     IntSize size([renderedImage size]);
634     size.scale(1 / frame->page()->deviceScaleFactor());
635     [renderedImage setSize:size];
636
637     return renderedImage.autorelease();
638 #else
639     return createDragImageForRange(*frame, range, forceBlackText).autorelease();
640 #endif
641 }
642
643 - (NSArray *)textRects
644 {
645     // FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
646     auto& range = *core(self);
647     Vector<WebCore::IntRect> rects;
648     range.ownerDocument().updateLayoutIgnorePendingStylesheets();
649     range.absoluteTextRects(rects);
650     return kit(rects);
651 }
652
653 - (NSArray *)lineBoxRects
654 {
655     // FIXME: Remove this once all clients stop using it and we drop Leopard support.
656     return [self textRects];
657 }
658
659 @end
660
661 //------------------------------------------------------------------------------------------
662 // DOMElement
663
664 @implementation DOMElement (DOMElementAppKitExtensions)
665
666 #if PLATFORM(MAC)
667
668 - (NSImage *)image
669 {
670     auto* renderer = core(self)->renderer();
671     if (!is<RenderImage>(renderer))
672         return nil;
673     auto* cachedImage = downcast<RenderImage>(*renderer).cachedImage();
674     if (!cachedImage || cachedImage->errorOccurred())
675         return nil;
676     return cachedImage->imageForRenderer(renderer)->nsImage();
677 }
678
679 #endif
680
681 @end
682
683 @implementation DOMElement (WebPrivate)
684
685 - (CTFontRef)_font
686 {
687     auto* renderer = core(self)->renderer();
688     if (!renderer)
689         return nil;
690     return renderer->style().fontCascade().primaryFont().getCTFont();
691 }
692
693 #if PLATFORM(MAC)
694
695 - (NSData *)_imageTIFFRepresentation
696 {
697     // FIXME: Could we move this function to WebCore::Element and autogenerate?
698     auto* renderer = core(self)->renderer();
699     if (!is<RenderImage>(renderer))
700         return nil;
701     auto* cachedImage = downcast<RenderImage>(*renderer).cachedImage();
702     if (!cachedImage || cachedImage->errorOccurred())
703         return nil;
704     return (NSData *)cachedImage->imageForRenderer(renderer)->tiffRepresentation();
705 }
706
707 #endif
708
709 - (NSURL *)_getURLAttribute:(NSString *)name
710 {
711     auto& element = *core(self);
712     return element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(element.getAttribute(name)));
713 }
714
715 - (BOOL)isFocused
716 {
717     auto& element = *core(self);
718     return element.document().focusedElement() == &element;
719 }
720
721 @end
722
723 #if PLATFORM(IOS)
724
725 @implementation DOMHTMLLinkElement (WebPrivate)
726
727 - (BOOL)_mediaQueryMatchesForOrientation:(int)orientation
728 {
729     Document& document = static_cast<HTMLLinkElement*>(core(self))->document();
730     FrameView* frameView = document.frame() ? document.frame()->view() : 0;
731     if (!frameView)
732         return false;
733     int layoutWidth = frameView->layoutWidth();
734     int layoutHeight = frameView->layoutHeight();
735     IntSize savedFixedLayoutSize = frameView->fixedLayoutSize();
736     bool savedUseFixedLayout = frameView->useFixedLayout();
737     if ((orientation == WebMediaQueryOrientationPortrait && layoutWidth > layoutHeight) ||
738         (orientation == WebMediaQueryOrientationLandscape && layoutWidth < layoutHeight)) {
739         // temporarily swap the orientation for the evaluation
740         frameView->setFixedLayoutSize(IntSize(layoutHeight, layoutWidth));
741         frameView->setUseFixedLayout(true);
742     }
743         
744     bool result = [self _mediaQueryMatches];
745
746     frameView->setFixedLayoutSize(savedFixedLayoutSize);
747     frameView->setUseFixedLayout(savedUseFixedLayout);
748
749     return result;
750 }
751
752 - (BOOL)_mediaQueryMatches
753 {
754     HTMLLinkElement& link = *static_cast<HTMLLinkElement*>(core(self));
755
756     auto& media = link.attributeWithoutSynchronization(HTMLNames::mediaAttr);
757     if (media.isEmpty())
758         return true;
759
760     Document& document = link.document();
761     auto mediaQuerySet = MediaQuerySet::create(media);
762     return MediaQueryEvaluator { "screen", document, document.renderView() ? &document.renderView()->style() : nullptr }.evaluate(mediaQuerySet.get());
763 }
764
765 @end
766
767 #endif
768
769 //------------------------------------------------------------------------------------------
770 // DOMRange
771
772 @implementation DOMRange (WebPrivate)
773
774 - (NSString *)description
775 {
776     if (!_internal)
777         return @"<DOMRange: null>";
778     return [NSString stringWithFormat:@"<DOMRange: %@ %d %@ %d>",
779                [self startContainer], [self startOffset], [self endContainer], [self endOffset]];
780 }
781
782 // FIXME: This should be removed as soon as all internal Apple uses of it have been replaced with
783 // calls to the public method - (NSString *)text.
784 - (NSString *)_text
785 {
786     return [self text];
787 }
788
789 @end
790
791 //------------------------------------------------------------------------------------------
792 // DOMRGBColor
793
794 @implementation DOMRGBColor (WebPrivate)
795
796 #if PLATFORM(MAC)
797
798 // FIXME: This should be removed as soon as all internal Apple uses of it have been replaced with
799 // calls to the public method - (NSColor *)color.
800 - (NSColor *)_color
801 {
802     return [self color];
803 }
804
805 #endif
806
807 @end
808
809 //------------------------------------------------------------------------------------------
810 // DOMHTMLTableCellElement
811
812 @implementation DOMHTMLTableCellElement (WebPrivate)
813
814 - (DOMHTMLTableCellElement *)_cellAbove
815 {
816     return kit(core(self)->cellAbove());
817 }
818
819 @end
820
821 //------------------------------------------------------------------------------------------
822 // DOMNodeFilter
823
824 DOMNodeFilter *kit(WebCore::NodeFilter* impl)
825 {
826     if (!impl)
827         return nil;
828     
829     if (DOMNodeFilter *wrapper = getDOMWrapper(impl))
830         return [[wrapper retain] autorelease];
831     
832     DOMNodeFilter *wrapper = [[DOMNodeFilter alloc] _init];
833     wrapper->_internal = reinterpret_cast<DOMObjectInternal*>(impl);
834     impl->ref();
835     addDOMWrapper(wrapper, impl);
836     return [wrapper autorelease];
837 }
838
839 WebCore::NodeFilter* core(DOMNodeFilter *wrapper)
840 {
841     return wrapper ? reinterpret_cast<WebCore::NodeFilter*>(wrapper->_internal) : 0;
842 }
843
844 @implementation DOMNodeFilter
845
846 - (void)dealloc
847 {
848     if (_internal)
849         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
850     [super dealloc];
851 }
852
853 - (void)finalize
854 {
855     if (_internal)
856         reinterpret_cast<WebCore::NodeFilter*>(_internal)->deref();
857     [super finalize];
858 }
859
860 - (short)acceptNode:(DOMNode *)node
861 {
862     if (!node)
863         raiseTypeErrorException();
864     
865     auto result = core(self)->acceptNode(*core(node));
866     return result.type() == CallbackResultType::Success ? result.releaseReturnValue() : NodeFilter::FILTER_REJECT;
867 }
868
869 @end