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