WebCore:
[WebKit-https.git] / WebCore / page / mac / FrameMac.mm
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "DOMWindow.h"
43 #import "DocumentLoader.h"
44 #import "EditCommand.h"
45 #import "EditorClient.h"
46 #import "Event.h"
47 #import "EventNames.h"
48 #import "FloatRect.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 "JSDOMWindow.h"
66 #import "KeyboardEvent.h"
67 #import "Logging.h"
68 #import "MouseEventWithHitTestResults.h"
69 #import "Page.h"
70 #import "PlatformKeyboardEvent.h"
71 #import "PlatformScrollBar.h"
72 #import "PlatformWheelEvent.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 "SimpleFontData.h"
83 #import "SystemTime.h"
84 #import "TextResourceDecoder.h"
85 #import "UserStyleSheetLoader.h"
86 #import "WebCoreViewFactory.h"
87 #import "WebDashboardRegion.h"
88 #import "WebScriptObjectPrivate.h"
89 #import "kjs_proxy.h"
90 #import "visible_units.h"
91 #import <Carbon/Carbon.h>
92 #import <JavaScriptCore/APICast.h>
93
94 #if ENABLE(NETSCAPE_PLUGIN_API)
95 #import "c_instance.h"
96 #import "NP_jsobject.h"
97 #import "npruntime_impl.h"
98 #endif
99 #import "objc_instance.h"
100 #import "runtime_root.h"
101 #import "runtime.h"
102 #import "jni_instance.h"
103
104 @interface NSObject (WebPlugin)
105 - (id)objectForWebScript;
106 - (NPObject *)createPluginScriptableObject;
107 @end
108  
109 @interface NSView (WebCoreHTMLDocumentView)
110 - (void)drawSingleRect:(NSRect)rect;
111 @end
112  
113 using namespace std;
114 using namespace KJS::Bindings;
115
116 using KJS::JSLock;
117
118 namespace WebCore {
119
120 using namespace EventNames;
121 using namespace HTMLNames;
122
123 // Either get cached regexp or build one that matches any of the labels.
124 // The regexp we build is of the form:  (STR1|STR2|STRN)
125 RegularExpression* regExpForLabels(NSArray* labels)
126 {
127     // All the ObjC calls in this method are simple array and string
128     // calls which we can assume do not raise exceptions
129
130
131     // Parallel arrays that we use to cache regExps.  In practice the number of expressions
132     // that the app will use is equal to the number of locales is used in searching.
133     static const unsigned int regExpCacheSize = 4;
134     static NSMutableArray* regExpLabels = nil;
135     static Vector<RegularExpression*> regExps;
136     static RegularExpression wordRegExp = RegularExpression("\\w");
137
138     RegularExpression* result;
139     if (!regExpLabels)
140         regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
141     CFIndex cacheHit = [regExpLabels indexOfObject:labels];
142     if (cacheHit != NSNotFound)
143         result = regExps.at(cacheHit);
144     else {
145         String pattern("(");
146         unsigned int numLabels = [labels count];
147         unsigned int i;
148         for (i = 0; i < numLabels; i++) {
149             String label = [labels objectAtIndex:i];
150
151             bool startsWithWordChar = false;
152             bool endsWithWordChar = false;
153             if (label.length() != 0) {
154                 startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0;
155                 endsWithWordChar = wordRegExp.search(label.substring(label.length() - 1, 1)) >= 0;
156             }
157             
158             if (i != 0)
159                 pattern.append("|");
160             // Search for word boundaries only if label starts/ends with "word characters".
161             // If we always searched for word boundaries, this wouldn't work for languages
162             // such as Japanese.
163             if (startsWithWordChar)
164                 pattern.append("\\b");
165             pattern.append(label);
166             if (endsWithWordChar)
167                 pattern.append("\\b");
168         }
169         pattern.append(")");
170         result = new RegularExpression(pattern, false);
171     }
172
173     // add regexp to the cache, making sure it is at the front for LRU ordering
174     if (cacheHit != 0) {
175         if (cacheHit != NSNotFound) {
176             // remove from old spot
177             [regExpLabels removeObjectAtIndex:cacheHit];
178             regExps.remove(cacheHit);
179         }
180         // add to start
181         [regExpLabels insertObject:labels atIndex:0];
182         regExps.insert(0, result);
183         // trim if too big
184         if ([regExpLabels count] > regExpCacheSize) {
185             [regExpLabels removeObjectAtIndex:regExpCacheSize];
186             RegularExpression* last = regExps.last();
187             regExps.removeLast();
188             delete last;
189         }
190     }
191     return result;
192 }
193
194 NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
195 {
196     RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
197
198     if (cellRenderer && cellRenderer->isTableCell()) {
199         RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
200
201         if (cellAboveRenderer) {
202             HTMLTableCellElement* aboveCell =
203                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
204
205             if (aboveCell) {
206                 // search within the above cell we found for a match
207                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
208                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
209                         // For each text chunk, run the regexp
210                         String nodeString = n->nodeValue();
211                         int pos = regExp->searchRev(nodeString);
212                         if (pos >= 0)
213                             return nodeString.substring(pos, regExp->matchedLength());
214                     }
215                 }
216             }
217         }
218     }
219     // Any reason in practice to search all cells in that are above cell?
220     return nil;
221 }
222
223 NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element)
224 {
225     RegularExpression* regExp = regExpForLabels(labels);
226     // We stop searching after we've seen this many chars
227     const unsigned int charsSearchedThreshold = 500;
228     // This is the absolute max we search.  We allow a little more slop than
229     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
230     const unsigned int maxCharsSearched = 600;
231     // If the starting element is within a table, the cell that contains it
232     HTMLTableCellElement* startingTableCell = 0;
233     bool searchedCellAbove = false;
234
235     // walk backwards in the node tree, until another element, or form, or end of tree
236     int unsigned lengthSearched = 0;
237     Node* n;
238     for (n = element->traversePreviousNode();
239          n && lengthSearched < charsSearchedThreshold;
240          n = n->traversePreviousNode())
241     {
242         if (n->hasTagName(formTag)
243             || (n->isHTMLElement()
244                 && static_cast<HTMLElement*>(n)->isGenericFormElement()))
245         {
246             // We hit another form element or the start of the form - bail out
247             break;
248         } else if (n->hasTagName(tdTag) && !startingTableCell) {
249             startingTableCell = static_cast<HTMLTableCellElement*>(n);
250         } else if (n->hasTagName(trTag) && startingTableCell) {
251             NSString* result = searchForLabelsAboveCell(regExp, startingTableCell);
252             if (result && [result length] > 0)
253                 return result;
254             searchedCellAbove = true;
255         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
256             // For each text chunk, run the regexp
257             String nodeString = n->nodeValue();
258             // add 100 for slop, to make it more likely that we'll search whole nodes
259             if (lengthSearched + nodeString.length() > maxCharsSearched)
260                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
261             int pos = regExp->searchRev(nodeString);
262             if (pos >= 0)
263                 return nodeString.substring(pos, regExp->matchedLength());
264
265             lengthSearched += nodeString.length();
266         }
267     }
268
269     // If we started in a cell, but bailed because we found the start of the form or the
270     // previous element, we still might need to search the row above us for a label.
271     if (startingTableCell && !searchedCellAbove) {
272         NSString* result = searchForLabelsAboveCell(regExp, startingTableCell);
273         if (result && [result length] > 0)
274             return result;
275     }
276     
277     return nil;
278 }
279
280 NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
281 {
282     String name = element->getAttribute(nameAttr);
283     if (name.isEmpty())
284         return nil;
285
286     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
287     replace(name, RegularExpression("\\d"), " ");
288     name.replace('_', ' ');
289
290     RegularExpression* regExp = regExpForLabels(labels);
291     // Use the largest match we can find in the whole name string
292     int pos;
293     int length;
294     int bestPos = -1;
295     int bestLength = -1;
296     int start = 0;
297     do {
298         pos = regExp->search(name, start);
299         if (pos != -1) {
300             length = regExp->matchedLength();
301             if (length >= bestLength) {
302                 bestPos = pos;
303                 bestLength = length;
304             }
305             start = pos + 1;
306         }
307     } while (pos != -1);
308
309     if (bestPos != -1)
310         return name.substring(bestPos, bestLength);
311     return nil;
312 }
313
314 NSImage* Frame::imageFromRect(NSRect rect) const
315 {
316     NSView* view = d->m_view->documentView();
317     if (!view)
318         return nil;
319     if (![view respondsToSelector:@selector(drawSingleRect:)])
320         return nil;
321     
322     NSImage* resultImage;
323     BEGIN_BLOCK_OBJC_EXCEPTIONS;
324     
325     NSRect bounds = [view bounds];
326     
327     // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
328     rect = [view convertRect:rect toView:nil];
329     rect.size.height = roundf(rect.size.height);
330     rect.size.width = roundf(rect.size.width);
331     rect = [view convertRect:rect fromView:nil];
332     
333     resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
334
335     if (rect.size.width != 0 && rect.size.height != 0) {
336         [resultImage setFlipped:YES];
337         [resultImage lockFocus];
338         CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
339         CGContextSaveGState(context);
340         CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
341
342         // Note: Must not call drawRect: here, because drawRect: assumes that it's called from AppKit's
343         // display machinery. It calls getRectsBeingDrawn:count:, which can only be called inside
344         // when a real AppKit display is underway.
345         [view drawSingleRect:rect];
346
347         CGContextRestoreGState(context);
348         [resultImage unlockFocus];
349         [resultImage setFlipped:NO];
350     }
351
352     return resultImage;
353
354     END_BLOCK_OBJC_EXCEPTIONS;
355     
356     return nil;
357 }
358
359 NSImage* Frame::selectionImage(bool forceBlackText) const
360 {
361     d->m_paintRestriction = forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly;
362     d->m_doc->updateLayout();
363     NSImage* result = imageFromRect(selectionRect());
364     d->m_paintRestriction = PaintRestrictionNone;
365     return result;
366 }
367
368 NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
369 {
370     RenderObject* renderer = node->renderer();
371     if (!renderer)
372         return nil;
373     
374     renderer->updateDragState(true);    // mark dragged nodes (so they pick up the right CSS)
375     d->m_doc->updateLayout();        // forces style recalc - needed since changing the drag state might
376                                         // imply new styles, plus JS could have changed other things
377     IntRect topLevelRect;
378     NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
379
380     d->m_elementToDraw = node;              // invoke special sub-tree drawing mode
381     NSImage* result = imageFromRect(paintingRect);
382     renderer->updateDragState(false);
383     d->m_doc->updateLayout();
384     d->m_elementToDraw = 0;
385
386     if (elementRect)
387         *elementRect = topLevelRect;
388     if (imageRect)
389         *imageRect = paintingRect;
390     return result;
391 }
392
393 NSDictionary* Frame::fontAttributesForSelectionStart() const
394 {
395     Node* nodeToRemove;
396     RenderStyle* style = styleForSelectionStart(nodeToRemove);
397     if (!style)
398         return nil;
399
400     NSMutableDictionary* result = [NSMutableDictionary dictionary];
401
402     if (style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
403         [result setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
404
405     if (style->font().primaryFont()->getNSFont())
406         [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
407
408     if (style->color().isValid() && style->color() != Color::black)
409         [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
410
411     ShadowData* shadow = style->textShadow();
412     if (shadow) {
413         NSShadow* s = [[NSShadow alloc] init];
414         [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)];
415         [s setShadowBlurRadius:shadow->blur];
416         [s setShadowColor:nsColor(shadow->color)];
417         [result setObject:s forKey:NSShadowAttributeName];
418     }
419
420     int decoration = style->textDecorationsInEffect();
421     if (decoration & LINE_THROUGH)
422         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
423
424     int superscriptInt = 0;
425     switch (style->verticalAlign()) {
426         case BASELINE:
427         case BOTTOM:
428         case BASELINE_MIDDLE:
429         case LENGTH:
430         case MIDDLE:
431         case TEXT_BOTTOM:
432         case TEXT_TOP:
433         case TOP:
434             break;
435         case SUB:
436             superscriptInt = -1;
437             break;
438         case SUPER:
439             superscriptInt = 1;
440             break;
441     }
442     if (superscriptInt)
443         [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
444
445     if (decoration & UNDERLINE)
446         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
447
448     if (nodeToRemove) {
449         ExceptionCode ec = 0;
450         nodeToRemove->remove(ec);
451         ASSERT(ec == 0);
452     }
453
454     return result;
455 }
456
457 NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const
458 {
459     NSWritingDirection result = NSWritingDirectionLeftToRight;
460
461     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
462     Node* node = pos.node();
463     if (!node || !node->renderer() || !node->renderer()->containingBlock())
464         return result;
465     RenderStyle* style = node->renderer()->containingBlock()->style();
466     if (!style)
467         return result;
468         
469     switch (style->direction()) {
470         case LTR:
471             result = NSWritingDirectionLeftToRight;
472             break;
473         case RTL:
474             result = NSWritingDirectionRightToLeft;
475             break;
476     }
477
478     return result;
479 }
480
481 const short enableRomanKeyboardsOnly = -23;
482 void Frame::setUseSecureKeyboardEntry(bool enable)
483 {
484     if (enable == IsSecureEventInputEnabled())
485         return;
486     if (enable) {
487         EnableSecureEventInput();
488 #ifdef BUILDING_ON_TIGER
489         KeyScript(enableRomanKeyboardsOnly);
490 #else
491         CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
492         TSMSetDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources);
493         CFRelease(inputSources);
494 #endif
495     } else {
496         DisableSecureEventInput();
497 #ifdef BUILDING_ON_TIGER
498         KeyScript(smKeyEnableKybds);
499 #else
500         TSMRemoveDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag);
501 #endif
502     }
503 }
504
505 NSMutableDictionary* Frame::dashboardRegionsDictionary()
506 {
507     Document* doc = document();
508     if (!doc)
509         return nil;
510
511     const Vector<DashboardRegionValue>& regions = doc->dashboardRegions();
512     size_t n = regions.size();
513
514     // Convert the Vector<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
515     NSMutableDictionary* webRegions = [NSMutableDictionary dictionaryWithCapacity:n];
516     for (size_t i = 0; i < n; i++) {
517         const DashboardRegionValue& region = regions[i];
518
519         if (region.type == StyleDashboardRegion::None)
520             continue;
521         
522         NSString *label = region.label;
523         WebDashboardRegionType type = WebDashboardRegionTypeNone;
524         if (region.type == StyleDashboardRegion::Circle)
525             type = WebDashboardRegionTypeCircle;
526         else if (region.type == StyleDashboardRegion::Rectangle)
527             type = WebDashboardRegionTypeRectangle;
528         NSMutableArray *regionValues = [webRegions objectForKey:label];
529         if (!regionValues) {
530             regionValues = [[NSMutableArray alloc] initWithCapacity:1];
531             [webRegions setObject:regionValues forKey:label];
532             [regionValues release];
533         }
534         
535         WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type];
536         [regionValues addObject:webRegion];
537         [webRegion release];
538     }
539     
540     return webRegions;
541 }
542
543 DragImageRef Frame::dragImageForSelection() 
544 {
545     if (!selectionController()->isRange())
546         return nil;
547     return selectionImage();
548 }
549
550 PassRefPtr<KJS::Bindings::Instance> Frame::createScriptInstanceForWidget(Widget* widget)
551 {
552     NSView* widgetView = widget->getView();
553     if (!widgetView)
554         return 0;
555
556     RefPtr<RootObject> rootObject = createRootObject(widgetView, scriptProxy()->globalObject());
557
558     if ([widgetView respondsToSelector:@selector(objectForWebScript)]) {
559         id objectForWebScript = [widgetView objectForWebScript];
560         if (!objectForWebScript)
561             return 0;
562         return KJS::Bindings::ObjcInstance::create(objectForWebScript, rootObject.release());
563     }
564
565     if ([widgetView respondsToSelector:@selector(createPluginScriptableObject)]) {
566 #if !ENABLE(NETSCAPE_PLUGIN_API)
567         return 0;
568 #else
569         NPObject* npObject = [widgetView createPluginScriptableObject];
570         if (!npObject)
571             return 0;
572         RefPtr<Instance> instance = KJS::Bindings::CInstance::create(npObject, rootObject.release());
573         // -createPluginScriptableObject returns a retained NPObject.  The caller is expected to release it.
574         _NPN_ReleaseObject(npObject);
575         return instance.release();
576 #endif
577     }
578
579     jobject applet = loader()->client()->javaApplet(widgetView);
580     if (!applet)
581         return 0;
582     return KJS::Bindings::JavaInstance::create(applet, rootObject.release());
583 }
584
585 WebScriptObject* Frame::windowScriptObject()
586 {
587     if (!scriptProxy()->isEnabled())
588         return 0;
589
590     if (!d->m_windowScriptObject) {
591         KJS::JSLock lock;
592         KJS::JSObject* win = toJSDOMWindow(this);
593         KJS::Bindings::RootObject *root = bindingRootObject();
594         d->m_windowScriptObject = [WebScriptObject scriptObjectForJSObject:toRef(win) originRootObject:root rootObject:root];
595     }
596
597     return d->m_windowScriptObject.get();
598 }
599
600 void Frame::clearPlatformScriptObjects()
601 {
602     if (d->m_windowScriptObject) {
603         KJS::Bindings::RootObject* root = bindingRootObject();
604         [d->m_windowScriptObject.get() _setOriginRootObject:root andRootObject:root];
605     }
606 }
607
608 void Frame::setUserStyleSheetLocation(const KURL& url)
609 {
610     delete d->m_userStyleSheetLoader;
611     d->m_userStyleSheetLoader = 0;
612     if (d->m_doc && d->m_doc->docLoader())
613         d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.string());
614 }
615
616 void Frame::setUserStyleSheet(const String& styleSheet)
617 {
618     delete d->m_userStyleSheetLoader;
619     d->m_userStyleSheetLoader = 0;
620     if (d->m_doc)
621         d->m_doc->setUserStyleSheet(styleSheet);
622 }
623
624 static pthread_t mainThread;
625
626 static void updateRenderingForBindings(KJS::ExecState* exec, KJS::JSObject* rootObject)
627 {
628     if (pthread_self() != mainThread)
629         return;
630         
631     if (!rootObject)
632         return;
633         
634     JSDOMWindow* window = static_cast<JSDOMWindow*>(rootObject);
635     if (!window)
636         return;
637
638     Frame* frame = window->impl()->frame();
639     if (!frame)
640         return;
641
642     Document* document = frame->document();
643     if (!document)
644         return;
645
646     document->updateRendering();
647 }
648
649 void Frame::initJavaJSBindings()
650 {
651     mainThread = pthread_self();
652     KJS::Bindings::JavaJSObject::initializeJNIThreading();
653     KJS::Bindings::Instance::setDidExecuteFunction(updateRenderingForBindings);
654 }
655
656 } // namespace WebCore