8f79298447ba3fbf3d9b436872b78a4e7d668c57
[WebKit-https.git] / WebCore / page / mac / FrameMac.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
4  * Copyright (C) 2007 Trolltech ASA
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 COMPUTER, 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 COMPUTER, 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 "config.h"
29 #import "Frame.h"
30
31 #import "AXObjectCache.h"
32 #import "BeforeUnloadEvent.h"
33 #import "BlockExceptions.h"
34 #import "CSSHelper.h"
35 #import "Cache.h"
36 #import "Chrome.h"
37 #import "ClipboardEvent.h"
38 #import "ClipboardMac.h"
39 #import "ColorMac.h"
40 #import "Cursor.h"
41 #import "DOMInternal.h"
42 #import "DocumentLoader.h"
43 #import "EditCommand.h"
44 #import "EditorClient.h"
45 #import "Event.h"
46 #import "EventNames.h"
47 #import "FloatRect.h"
48 #import "FontData.h"
49 #import "FoundationExtras.h"
50 #import "FrameLoadRequest.h"
51 #import "FrameLoader.h"
52 #import "FrameLoaderClient.h"
53 #import "FrameLoaderTypes.h"
54 #import "FramePrivate.h"
55 #import "FrameView.h"
56 #import "GraphicsContext.h"
57 #import "HTMLDocument.h"
58 #import "HTMLFormElement.h"
59 #import "HTMLGenericFormElement.h"
60 #import "HTMLInputElement.h"
61 #import "HTMLNames.h"
62 #import "HTMLTableCellElement.h"
63 #import "HitTestRequest.h"
64 #import "HitTestResult.h"
65 #import "KeyboardEvent.h"
66 #import "Logging.h"
67 #import "MouseEventWithHitTestResults.h"
68 #import "Page.h"
69 #import "PlatformKeyboardEvent.h"
70 #import "PlatformScrollBar.h"
71 #import "PlatformWheelEvent.h"
72 #import "Plugin.h"
73 #import "RegularExpression.h"
74 #import "RenderImage.h"
75 #import "RenderListItem.h"
76 #import "RenderPart.h"
77 #import "RenderTableCell.h"
78 #import "RenderTheme.h"
79 #import "RenderView.h"
80 #import "ResourceHandle.h"
81 #import "Settings.h"
82 #import "SystemTime.h"
83 #import "TextResourceDecoder.h"
84 #import "WebCoreFrameBridge.h"
85 #import "WebCoreSystemInterface.h"
86 #import "WebCoreViewFactory.h"
87 #import "WebDashboardRegion.h"
88 #import "WebScriptObjectPrivate.h"
89 #import "kjs_proxy.h"
90 #import "kjs_window.h"
91 #import "visible_units.h"
92 #import <Carbon/Carbon.h>
93 #import <JavaScriptCore/NP_jsobject.h>
94 #import <JavaScriptCore/npruntime_impl.h>
95
96 #undef _webcore_TIMING
97
98 @interface NSObject (WebPlugIn)
99 - (id)objectForWebScript;
100 - (NPObject *)createPluginScriptableObject;
101 @end
102  
103 @interface NSView (WebCoreHTMLDocumentView)
104 - (void)drawSingleRect:(NSRect)rect;
105 @end
106  
107 using namespace std;
108 using namespace KJS::Bindings;
109
110 using KJS::JSLock;
111
112 namespace WebCore {
113
114 using namespace EventNames;
115 using namespace HTMLNames;
116
117 void Frame::setBridge(WebCoreFrameBridge* bridge)
118
119     if (d->m_bridge == bridge)
120         return;
121
122     if (!bridge) {
123         [d->m_bridge clearFrame];
124         HardRelease(d->m_bridge);
125         d->m_bridge = nil;
126         return;
127     }
128     HardRetain(bridge);
129     HardRelease(d->m_bridge);
130     d->m_bridge = bridge;
131 }
132
133 WebCoreFrameBridge* Frame::bridge() const
134 {
135     return d->m_bridge;
136 }
137
138 // Either get cached regexp or build one that matches any of the labels.
139 // The regexp we build is of the form:  (STR1|STR2|STRN)
140 RegularExpression* regExpForLabels(NSArray* labels)
141 {
142     // All the ObjC calls in this method are simple array and string
143     // calls which we can assume do not raise exceptions
144
145
146     // Parallel arrays that we use to cache regExps.  In practice the number of expressions
147     // that the app will use is equal to the number of locales is used in searching.
148     static const unsigned int regExpCacheSize = 4;
149     static NSMutableArray* regExpLabels = nil;
150     static Vector<RegularExpression*> regExps;
151     static RegularExpression wordRegExp = RegularExpression("\\w");
152
153     RegularExpression* result;
154     if (!regExpLabels)
155         regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
156     CFIndex cacheHit = [regExpLabels indexOfObject:labels];
157     if (cacheHit != NSNotFound)
158         result = regExps.at(cacheHit);
159     else {
160         DeprecatedString pattern("(");
161         unsigned int numLabels = [labels count];
162         unsigned int i;
163         for (i = 0; i < numLabels; i++) {
164             DeprecatedString label = DeprecatedString::fromNSString((NSString*)[labels objectAtIndex:i]);
165
166             bool startsWithWordChar = false;
167             bool endsWithWordChar = false;
168             if (label.length() != 0) {
169                 startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
170                 endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
171             }
172             
173             if (i != 0)
174                 pattern.append("|");
175             // Search for word boundaries only if label starts/ends with "word characters".
176             // If we always searched for word boundaries, this wouldn't work for languages
177             // such as Japanese.
178             if (startsWithWordChar) {
179                 pattern.append("\\b");
180             }
181             pattern.append(label);
182             if (endsWithWordChar) {
183                 pattern.append("\\b");
184             }
185         }
186         pattern.append(")");
187         result = new RegularExpression(pattern, false);
188     }
189
190     // add regexp to the cache, making sure it is at the front for LRU ordering
191     if (cacheHit != 0) {
192         if (cacheHit != NSNotFound) {
193             // remove from old spot
194             [regExpLabels removeObjectAtIndex:cacheHit];
195             regExps.remove(cacheHit);
196         }
197         // add to start
198         [regExpLabels insertObject:labels atIndex:0];
199         regExps.insert(0, result);
200         // trim if too big
201         if ([regExpLabels count] > regExpCacheSize) {
202             [regExpLabels removeObjectAtIndex:regExpCacheSize];
203             RegularExpression* last = regExps.last();
204             regExps.removeLast();
205             delete last;
206         }
207     }
208     return result;
209 }
210
211 NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
212 {
213     RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
214
215     if (cellRenderer && cellRenderer->isTableCell()) {
216         RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
217
218         if (cellAboveRenderer) {
219             HTMLTableCellElement* aboveCell =
220                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
221
222             if (aboveCell) {
223                 // search within the above cell we found for a match
224                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
225                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
226                         // For each text chunk, run the regexp
227                         DeprecatedString nodeString = n->nodeValue().deprecatedString();
228                         int pos = regExp->searchRev(nodeString);
229                         if (pos >= 0)
230                             return nodeString.mid(pos, regExp->matchedLength()).getNSString();
231                     }
232                 }
233             }
234         }
235     }
236     // Any reason in practice to search all cells in that are above cell?
237     return nil;
238 }
239
240 NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element)
241 {
242     RegularExpression* regExp = regExpForLabels(labels);
243     // We stop searching after we've seen this many chars
244     const unsigned int charsSearchedThreshold = 500;
245     // This is the absolute max we search.  We allow a little more slop than
246     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
247     const unsigned int maxCharsSearched = 600;
248     // If the starting element is within a table, the cell that contains it
249     HTMLTableCellElement* startingTableCell = 0;
250     bool searchedCellAbove = false;
251
252     // walk backwards in the node tree, until another element, or form, or end of tree
253     int unsigned lengthSearched = 0;
254     Node* n;
255     for (n = element->traversePreviousNode();
256          n && lengthSearched < charsSearchedThreshold;
257          n = n->traversePreviousNode())
258     {
259         if (n->hasTagName(formTag)
260             || (n->isHTMLElement()
261                 && static_cast<HTMLElement*>(n)->isGenericFormElement()))
262         {
263             // We hit another form element or the start of the form - bail out
264             break;
265         } else if (n->hasTagName(tdTag) && !startingTableCell) {
266             startingTableCell = static_cast<HTMLTableCellElement*>(n);
267         } else if (n->hasTagName(trTag) && startingTableCell) {
268             NSString* result = searchForLabelsAboveCell(regExp, startingTableCell);
269             if (result && [result length] > 0)
270                 return result;
271             searchedCellAbove = true;
272         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
273             // For each text chunk, run the regexp
274             DeprecatedString nodeString = n->nodeValue().deprecatedString();
275             // add 100 for slop, to make it more likely that we'll search whole nodes
276             if (lengthSearched + nodeString.length() > maxCharsSearched)
277                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
278             int pos = regExp->searchRev(nodeString);
279             if (pos >= 0)
280                 return nodeString.mid(pos, regExp->matchedLength()).getNSString();
281
282             lengthSearched += nodeString.length();
283         }
284     }
285
286     // If we started in a cell, but bailed because we found the start of the form or the
287     // previous element, we still might need to search the row above us for a label.
288     if (startingTableCell && !searchedCellAbove) {
289         NSString* result = searchForLabelsAboveCell(regExp, startingTableCell);
290         if (result && [result length] > 0)
291             return result;
292     }
293     
294     return nil;
295 }
296
297 NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
298 {
299     DeprecatedString name = element->getAttribute(nameAttr).deprecatedString();
300     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
301     name.replace(RegularExpression("[[:digit:]]"), " ");
302     name.replace('_', ' ');
303     
304     RegularExpression* regExp = regExpForLabels(labels);
305     // Use the largest match we can find in the whole name string
306     int pos;
307     int length;
308     int bestPos = -1;
309     int bestLength = -1;
310     int start = 0;
311     do {
312         pos = regExp->search(name, start);
313         if (pos != -1) {
314             length = regExp->matchedLength();
315             if (length >= bestLength) {
316                 bestPos = pos;
317                 bestLength = length;
318             }
319             start = pos+1;
320         }
321     } while (pos != -1);
322
323     if (bestPos != -1)
324         return name.mid(bestPos, bestLength).getNSString();
325     return nil;
326 }
327
328 NSImage* Frame::imageFromRect(NSRect rect) const
329 {
330     NSView* view = d->m_view->getDocumentView();
331     if (!view)
332         return nil;
333     if (![view respondsToSelector:@selector(drawSingleRect:)])
334         return nil;
335     
336     NSImage* resultImage;
337     BEGIN_BLOCK_OBJC_EXCEPTIONS;
338     
339     NSRect bounds = [view bounds];
340     
341     // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
342     rect = [view convertRect:rect toView:nil];
343     rect.size.height = roundf(rect.size.height);
344     rect.size.width = roundf(rect.size.width);
345     rect = [view convertRect:rect fromView:nil];
346     
347     resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
348
349     if (rect.size.width != 0 && rect.size.height != 0) {
350         [resultImage setFlipped:YES];
351         [resultImage lockFocus];
352         CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
353         CGContextSaveGState(context);
354         CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
355
356         // Note: Must not call drawRect: here, because drawRect: assumes that it's called from AppKit's
357         // display machinery. It calls getRectsBeingDrawn:count:, which can only be called inside
358         // when a real AppKit display is underway.
359         [view drawSingleRect:rect];
360
361         CGContextRestoreGState(context);
362         [resultImage unlockFocus];
363         [resultImage setFlipped:NO];
364     }
365
366     return resultImage;
367
368     END_BLOCK_OBJC_EXCEPTIONS;
369     
370     return nil;
371 }
372
373 NSImage* Frame::selectionImage(bool forceBlackText) const
374 {
375     d->m_paintRestriction = forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly;
376     d->m_doc->updateLayout();
377     NSImage* result = imageFromRect(selectionRect());
378     d->m_paintRestriction = PaintRestrictionNone;
379     return result;
380 }
381
382 NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
383 {
384     RenderObject* renderer = node->renderer();
385     if (!renderer)
386         return nil;
387     
388     renderer->updateDragState(true);    // mark dragged nodes (so they pick up the right CSS)
389     d->m_doc->updateLayout();        // forces style recalc - needed since changing the drag state might
390                                         // imply new styles, plus JS could have changed other things
391     IntRect topLevelRect;
392     NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
393
394     d->m_elementToDraw = node;              // invoke special sub-tree drawing mode
395     NSImage* result = imageFromRect(paintingRect);
396     renderer->updateDragState(false);
397     d->m_doc->updateLayout();
398     d->m_elementToDraw = 0;
399
400     if (elementRect)
401         *elementRect = topLevelRect;
402     if (imageRect)
403         *imageRect = paintingRect;
404     return result;
405 }
406
407 NSDictionary* Frame::fontAttributesForSelectionStart() const
408 {
409     Node* nodeToRemove;
410     RenderStyle* style = styleForSelectionStart(nodeToRemove);
411     if (!style)
412         return nil;
413
414     NSMutableDictionary* result = [NSMutableDictionary dictionary];
415
416     if (style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
417         [result setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
418
419     if (style->font().primaryFont()->getNSFont())
420         [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
421
422     if (style->color().isValid() && style->color() != Color::black)
423         [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
424
425     ShadowData* shadow = style->textShadow();
426     if (shadow) {
427         NSShadow* s = [[NSShadow alloc] init];
428         [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)];
429         [s setShadowBlurRadius:shadow->blur];
430         [s setShadowColor:nsColor(shadow->color)];
431         [result setObject:s forKey:NSShadowAttributeName];
432     }
433
434     int decoration = style->textDecorationsInEffect();
435     if (decoration & LINE_THROUGH)
436         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
437
438     int superscriptInt = 0;
439     switch (style->verticalAlign()) {
440         case BASELINE:
441         case BOTTOM:
442         case BASELINE_MIDDLE:
443         case LENGTH:
444         case MIDDLE:
445         case TEXT_BOTTOM:
446         case TEXT_TOP:
447         case TOP:
448             break;
449         case SUB:
450             superscriptInt = -1;
451             break;
452         case SUPER:
453             superscriptInt = 1;
454             break;
455     }
456     if (superscriptInt)
457         [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
458
459     if (decoration & UNDERLINE)
460         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
461
462     if (nodeToRemove) {
463         ExceptionCode ec = 0;
464         nodeToRemove->remove(ec);
465         ASSERT(ec == 0);
466     }
467
468     return result;
469 }
470
471 NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const
472 {
473     NSWritingDirection result = NSWritingDirectionLeftToRight;
474
475     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
476     Node* node = pos.node();
477     if (!node || !node->renderer() || !node->renderer()->containingBlock())
478         return result;
479     RenderStyle* style = node->renderer()->containingBlock()->style();
480     if (!style)
481         return result;
482         
483     switch (style->direction()) {
484         case LTR:
485             result = NSWritingDirectionLeftToRight;
486             break;
487         case RTL:
488             result = NSWritingDirectionRightToLeft;
489             break;
490     }
491
492     return result;
493 }
494
495 void Frame::issuePasteCommand()
496 {
497     [d->m_bridge issuePasteCommand];
498 }
499
500 void Frame::issueTransposeCommand()
501 {
502     [d->m_bridge issueTransposeCommand];
503 }
504
505 const short enableRomanKeyboardsOnly = -23;
506 void Frame::setUseSecureKeyboardEntry(bool enable)
507 {
508     if (enable == IsSecureEventInputEnabled())
509         return;
510     if (enable) {
511         EnableSecureEventInput();
512 #ifdef BUILDING_ON_TIGER
513         KeyScript(enableRomanKeyboardsOnly);
514 #else
515         CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
516         TSMSetDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources);
517         CFRelease(inputSources);
518 #endif
519     } else {
520         DisableSecureEventInput();
521 #ifdef BUILDING_ON_TIGER
522         KeyScript(smKeyEnableKybds);
523 #else
524         TSMRemoveDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag);
525 #endif
526     }
527 }
528
529 static void convertAttributesToUnderlines(Vector<MarkedTextUnderline>& result, const Range* markedTextRange, NSArray* attributes, NSArray* ranges)
530 {
531     int exception = 0;
532     int baseOffset = markedTextRange->startOffset(exception);
533
534     unsigned length = [attributes count];
535     ASSERT([ranges count] == length);
536
537     for (unsigned i = 0; i < length; i++) {
538         NSNumber* style = [[attributes objectAtIndex:i] objectForKey:NSUnderlineStyleAttributeName];
539         if (!style)
540             continue;
541         NSRange range = [[ranges objectAtIndex:i] rangeValue];
542         NSColor* color = [[attributes objectAtIndex:i] objectForKey:NSUnderlineColorAttributeName];
543         Color qColor = Color::black;
544         if (color)
545             qColor = colorFromNSColor([color colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
546
547         result.append(MarkedTextUnderline(range.location + baseOffset, 
548                                           range.location + baseOffset + range.length, 
549                                           qColor,
550                                           [style intValue] > 1));
551     }
552 }
553
554 void Frame::setMarkedTextRange(Range* range, NSArray* attributes, NSArray* ranges)
555 {
556     int exception;
557     exception = 0;
558
559     ASSERT(!range || range->startContainer(exception) == range->endContainer(exception));
560     ASSERT(!range || range->collapsed(exception) || range->startContainer(exception)->isTextNode());
561
562     Vector<MarkedTextUnderline> decorations;
563     if (attributes)
564         convertAttributesToUnderlines(decorations, range, attributes, ranges);
565     
566     setMarkedTextRange(range, decorations);
567 }
568
569 NSMutableDictionary* Frame::dashboardRegionsDictionary()
570 {
571     Document* doc = document();
572     if (!doc)
573         return nil;
574
575     const Vector<DashboardRegionValue>& regions = doc->dashboardRegions();
576     size_t n = regions.size();
577
578     // Convert the Vector<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
579     NSMutableDictionary* webRegions = [NSMutableDictionary dictionaryWithCapacity:n];
580     for (size_t i = 0; i < n; i++) {
581         const DashboardRegionValue& region = regions[i];
582
583         if (region.type == StyleDashboardRegion::None)
584             continue;
585         
586         NSString *label = region.label;
587         WebDashboardRegionType type = WebDashboardRegionTypeNone;
588         if (region.type == StyleDashboardRegion::Circle)
589             type = WebDashboardRegionTypeCircle;
590         else if (region.type == StyleDashboardRegion::Rectangle)
591             type = WebDashboardRegionTypeRectangle;
592         NSMutableArray *regionValues = [webRegions objectForKey:label];
593         if (!regionValues) {
594             regionValues = [[NSMutableArray alloc] initWithCapacity:1];
595             [webRegions setObject:regionValues forKey:label];
596             [regionValues release];
597         }
598         
599         WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type];
600         [regionValues addObject:webRegion];
601         [webRegion release];
602     }
603     
604     return webRegions;
605 }
606
607 void Frame::dashboardRegionsChanged()
608 {
609     NSMutableDictionary *webRegions = dashboardRegionsDictionary();
610     [d->m_bridge dashboardRegionsChanged:webRegions];
611 }
612
613 void Frame::willPopupMenu(NSMenu * menu)
614 {
615     [d->m_bridge willPopupMenu:menu];
616 }
617
618 void Frame::setNeedsReapplyStyles()
619 {
620     [d->m_bridge setNeedsReapplyStyles];
621 }
622
623 FloatRect Frame::customHighlightLineRect(const AtomicString& type, const FloatRect& lineRect, Node* node)
624 {
625     return [d->m_bridge customHighlightRect:type forLine:lineRect representedNode:node];
626 }
627
628 void Frame::paintCustomHighlight(const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, bool text, bool line, Node* node)
629 {
630     [d->m_bridge paintCustomHighlight:type forBox:boxRect onLine:lineRect behindText:text entireLine:line representedNode:node];
631 }
632
633 DragImageRef Frame::dragImageForSelection() 
634 {
635     if (!selectionController()->isRange())
636         return nil;
637     return selectionImage();
638 }
639
640
641 KJS::Bindings::Instance* Frame::createScriptInstanceForWidget(WebCore::Widget* widget)
642 {
643     NSView* aView = widget->getView();
644     if (!aView)
645         return 0;
646
647     void* nativeHandle = aView;
648     CreateRootObjectFunction createRootObject = RootObject::createRootObject();
649     RefPtr<RootObject> rootObject = createRootObject(nativeHandle);
650
651     if ([aView respondsToSelector:@selector(objectForWebScript)]) {
652         id objectForWebScript = [aView objectForWebScript];
653         if (objectForWebScript)
654             return Instance::createBindingForLanguageInstance(Instance::ObjectiveCLanguage, objectForWebScript, rootObject.release());
655         return 0;
656     } else if ([aView respondsToSelector:@selector(createPluginScriptableObject)]) {
657 #if USE(NPOBJECT)
658         NPObject* npObject = [aView createPluginScriptableObject];
659         if (npObject) {
660             Instance* instance = Instance::createBindingForLanguageInstance(Instance::CLanguage, npObject, rootObject.release());
661
662             // -createPluginScriptableObject returns a retained NPObject.  The caller is expected to release it.
663             _NPN_ReleaseObject(npObject);
664             return instance;
665         }
666 #endif
667         return 0;
668     }
669
670     jobject applet;
671     
672     // Get a pointer to the actual Java applet instance.
673     if ([d->m_bridge respondsToSelector:@selector(getAppletInView:)])
674         applet = [d->m_bridge getAppletInView:aView];
675     else
676         applet = [d->m_bridge pollForAppletInView:aView];
677     
678     if (applet) {
679         // Wrap the Java instance in a language neutral binding and hand
680         // off ownership to the APPLET element.
681         Instance* instance = Instance::createBindingForLanguageInstance(Instance::JavaLanguage, applet, rootObject.release());
682         return instance;
683     }
684     
685     return 0;
686 }
687
688 WebScriptObject* Frame::windowScriptObject()
689 {
690     Settings* settings = this->settings();
691     if (!settings || !settings->isJavaScriptEnabled())
692         return 0;
693
694     if (!d->m_windowScriptObject) {
695         KJS::JSLock lock;
696         KJS::JSObject* win = KJS::Window::retrieveWindow(this);
697         KJS::Bindings::RootObject *root = bindingRootObject();
698         d->m_windowScriptObject = HardRetain([WebScriptObject scriptObjectForJSObject:toRef(win) originRootObject:root rootObject:root]);
699     }
700
701     return d->m_windowScriptObject;
702 }
703
704 void Frame::cleanupPlatformScriptObjects()
705 {
706     HardRelease(d->m_windowScriptObject);
707     // Explicitly remove m_windowScriptObject from the wrapper caches, otherwise
708     // the next load might end up with a stale, cached m_windowScriptObject.
709     // (This problem is unique to m_windowScriptObject because its JS/DOM counterparts
710     // persist across page loads.)
711     removeDOMWrapper(reinterpret_cast<DOMObjectInternal*>(d->m_domWindow.get()));
712     if (d->m_jscript && d->m_jscript->haveInterpreter())
713         removeJSWrapper(KJS::Window::retrieveWindow(this));
714     d->m_windowScriptObject = 0;
715 }
716
717 } // namespace WebCore