FrameMac.mm 22.6 KB
Newer Older
rjw's avatar
rjw committed
1
/*
2
 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
ap's avatar
ap committed
3
 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
mjs's avatar
mjs committed
4
 * Copyright (C) 2007 Trolltech ASA
rjw's avatar
rjw committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
27

darin's avatar
darin committed
28
#import "config.h"
mjs's avatar
mjs committed
29
#import "Frame.h"
30

31
#import "AXObjectCache.h"
weinig's avatar
 
weinig committed
32
#import "BeforeUnloadEvent.h"
darin's avatar
darin committed
33
#import "BlockExceptions.h"
weinig's avatar
weinig committed
34
#import "CSSHelper.h"
darin's avatar
darin committed
35
#import "Cache.h"
weinig's avatar
weinig committed
36
#import "Chrome.h"
weinig's avatar
 
weinig committed
37
#import "ClipboardEvent.h"
bdakin's avatar
bdakin committed
38
#import "ClipboardMac.h"
sullivan's avatar
sullivan committed
39
#import "ColorMac.h"
darin's avatar
darin committed
40
#import "Cursor.h"
darin's avatar
darin committed
41
#import "DOMInternal.h"
darin's avatar
darin committed
42
#import "DocumentLoader.h"
darin's avatar
darin committed
43 44
#import "EditCommand.h"
#import "EditorClient.h"
weinig's avatar
 
weinig committed
45
#import "Event.h"
darin's avatar
darin committed
46
#import "EventNames.h"
47
#import "FloatRect.h"
darin's avatar
darin committed
48
#import "FontData.h"
darin's avatar
darin committed
49
#import "FoundationExtras.h"
mjs's avatar
mjs committed
50
#import "FrameLoadRequest.h"
ggaren's avatar
ggaren committed
51
#import "FrameLoader.h"
darin's avatar
darin committed
52
#import "FrameLoaderClient.h"
beidson's avatar
beidson committed
53
#import "FrameLoaderTypes.h"
ggaren's avatar
ggaren committed
54
#import "FramePrivate.h"
darin's avatar
darin committed
55
#import "FrameView.h"
darin's avatar
darin committed
56
#import "GraphicsContext.h"
darin's avatar
darin committed
57
#import "HTMLDocument.h"
darin's avatar
darin committed
58 59
#import "HTMLFormElement.h"
#import "HTMLGenericFormElement.h"
adele's avatar
adele committed
60
#import "HTMLInputElement.h"
61 62
#import "HTMLNames.h"
#import "HTMLTableCellElement.h"
bdakin's avatar
bdakin committed
63
#import "HitTestRequest.h"
darin's avatar
darin committed
64
#import "HitTestResult.h"
darin's avatar
darin committed
65
#import "KeyboardEvent.h"
darin's avatar
darin committed
66 67
#import "Logging.h"
#import "MouseEventWithHitTestResults.h"
darin's avatar
darin committed
68
#import "Page.h"
darin's avatar
darin committed
69
#import "PlatformKeyboardEvent.h"
70
#import "PlatformScrollBar.h"
darin's avatar
darin committed
71
#import "PlatformWheelEvent.h"
mjs's avatar
mjs committed
72
#import "Plugin.h"
darin's avatar
darin committed
73 74
#import "RegularExpression.h"
#import "RenderImage.h"
75
#import "RenderListItem.h"
76
#import "RenderPart.h"
darin's avatar
darin committed
77
#import "RenderTableCell.h"
darin's avatar
darin committed
78
#import "RenderTheme.h"
weinig's avatar
 
weinig committed
79
#import "RenderView.h"
mjs's avatar
mjs committed
80
#import "ResourceHandle.h"
ggaren's avatar
ggaren committed
81
#import "Settings.h"
darin's avatar
darin committed
82 83
#import "SystemTime.h"
#import "TextResourceDecoder.h"
mjs's avatar
mjs committed
84
#import "WebCoreFrameBridge.h"
ggaren's avatar
ggaren committed
85
#import "WebCoreSystemInterface.h"
mjs's avatar
mjs committed
86
#import "WebCoreViewFactory.h"
darin's avatar
darin committed
87
#import "WebDashboardRegion.h"
thatcher's avatar
thatcher committed
88
#import "WebScriptObjectPrivate.h"
darin's avatar
darin committed
89
#import "kjs_proxy.h"
mjs's avatar
mjs committed
90
#import "kjs_window.h"
darin's avatar
darin committed
91
#import "visible_units.h"
adele's avatar
adele committed
92
#import <Carbon/Carbon.h>
darin's avatar
darin committed
93 94
#import <JavaScriptCore/NP_jsobject.h>
#import <JavaScriptCore/npruntime_impl.h>
harrison's avatar
harrison committed
95

darin's avatar
darin committed
96
#undef _webcore_TIMING
97

darin's avatar
darin committed
98 99
@interface NSObject (WebPlugIn)
- (id)objectForWebScript;
tomernic's avatar
tomernic committed
100
- (NPObject *)createPluginScriptableObject;
darin's avatar
darin committed
101
@end
mjs's avatar
mjs committed
102
 
103 104 105 106
@interface NSView (WebCoreHTMLDocumentView)
- (void)drawSingleRect:(NSRect)rect;
@end
 
darin's avatar
darin committed
107
using namespace std;
darin's avatar
darin committed
108
using namespace KJS::Bindings;
darin's avatar
darin committed
109

darin's avatar
darin committed
110 111
using KJS::JSLock;

darin's avatar
darin committed
112 113 114 115
namespace WebCore {

using namespace EventNames;
using namespace HTMLNames;
darin's avatar
darin committed
116

mjs's avatar
mjs committed
117 118 119 120
void Frame::setBridge(WebCoreFrameBridge* bridge)
{ 
    if (d->m_bridge == bridge)
        return;
adele's avatar
adele committed
121

mjs's avatar
mjs committed
122 123 124 125 126 127 128 129 130
    if (!bridge) {
        [d->m_bridge clearFrame];
        HardRelease(d->m_bridge);
        d->m_bridge = nil;
        return;
    }
    HardRetain(bridge);
    HardRelease(d->m_bridge);
    d->m_bridge = bridge;
131
}
rjw's avatar
rjw committed
132

mjs's avatar
mjs committed
133
WebCoreFrameBridge* Frame::bridge() const
darin's avatar
darin committed
134
{
mjs's avatar
mjs committed
135
    return d->m_bridge;
darin's avatar
darin committed
136 137
}

trey's avatar
trey committed
138
// Either get cached regexp or build one that matches any of the labels.
sullivan's avatar
sullivan committed
139
// The regexp we build is of the form:  (STR1|STR2|STRN)
mjs's avatar
mjs committed
140
RegularExpression* regExpForLabels(NSArray* labels)
trey's avatar
trey committed
141
{
mjs's avatar
mjs committed
142 143 144 145
    // All the ObjC calls in this method are simple array and string
    // calls which we can assume do not raise exceptions


trey's avatar
trey committed
146 147 148
    // Parallel arrays that we use to cache regExps.  In practice the number of expressions
    // that the app will use is equal to the number of locales is used in searching.
    static const unsigned int regExpCacheSize = 4;
mjs's avatar
mjs committed
149
    static NSMutableArray* regExpLabels = nil;
150
    static Vector<RegularExpression*> regExps;
darin's avatar
darin committed
151
    static RegularExpression wordRegExp = RegularExpression("\\w");
trey's avatar
trey committed
152

mjs's avatar
mjs committed
153
    RegularExpression* result;
154
    if (!regExpLabels)
trey's avatar
trey committed
155
        regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
thatcher's avatar
thatcher committed
156
    CFIndex cacheHit = [regExpLabels indexOfObject:labels];
157
    if (cacheHit != NSNotFound)
trey's avatar
trey committed
158
        result = regExps.at(cacheHit);
159
    else {
darin's avatar
darin committed
160
        DeprecatedString pattern("(");
trey's avatar
trey committed
161 162 163
        unsigned int numLabels = [labels count];
        unsigned int i;
        for (i = 0; i < numLabels; i++) {
mjs's avatar
mjs committed
164
            DeprecatedString label = DeprecatedString::fromNSString((NSString*)[labels objectAtIndex:i]);
sullivan's avatar
sullivan committed
165 166 167 168 169 170 171 172

            bool startsWithWordChar = false;
            bool endsWithWordChar = false;
            if (label.length() != 0) {
                startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
                endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
            }
            
173
            if (i != 0)
trey's avatar
trey committed
174
                pattern.append("|");
sullivan's avatar
sullivan committed
175 176 177 178 179 180
            // Search for word boundaries only if label starts/ends with "word characters".
            // If we always searched for word boundaries, this wouldn't work for languages
            // such as Japanese.
            if (startsWithWordChar) {
                pattern.append("\\b");
            }
trey's avatar
trey committed
181
            pattern.append(label);
sullivan's avatar
sullivan committed
182 183 184
            if (endsWithWordChar) {
                pattern.append("\\b");
            }
trey's avatar
trey committed
185
        }
sullivan's avatar
sullivan committed
186
        pattern.append(")");
darin's avatar
darin committed
187
        result = new RegularExpression(pattern, false);
trey's avatar
trey committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    }

    // add regexp to the cache, making sure it is at the front for LRU ordering
    if (cacheHit != 0) {
        if (cacheHit != NSNotFound) {
            // remove from old spot
            [regExpLabels removeObjectAtIndex:cacheHit];
            regExps.remove(cacheHit);
        }
        // add to start
        [regExpLabels insertObject:labels atIndex:0];
        regExps.insert(0, result);
        // trim if too big
        if ([regExpLabels count] > regExpCacheSize) {
            [regExpLabels removeObjectAtIndex:regExpCacheSize];
mjs's avatar
mjs committed
203
            RegularExpression* last = regExps.last();
trey's avatar
trey committed
204 205 206 207 208 209
            regExps.removeLast();
            delete last;
        }
    }
    return result;
}
210

mjs's avatar
mjs committed
211
NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
212
{
213
    RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
214

bdakin's avatar
bdakin committed
215
    if (cellRenderer && cellRenderer->isTableCell()) {
216
        RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
217 218

        if (cellAboveRenderer) {
mjs's avatar
mjs committed
219
            HTMLTableCellElement* aboveCell =
220
                static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
221 222 223

            if (aboveCell) {
                // search within the above cell we found for a match
mjs's avatar
mjs committed
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
darin's avatar
darin committed
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 237 238
                }
            }
        }
    }
    // Any reason in practice to search all cells in that are above cell?
    return nil;
}
trey's avatar
trey committed
239

mjs's avatar
mjs committed
240
NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element)
trey's avatar
trey committed
241
{
mjs's avatar
mjs committed
242
    RegularExpression* regExp = regExpForLabels(labels);
trey's avatar
trey committed
243 244
    // We stop searching after we've seen this many chars
    const unsigned int charsSearchedThreshold = 500;
245 246
    // This is the absolute max we search.  We allow a little more slop than
    // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
trey's avatar
trey committed
247
    const unsigned int maxCharsSearched = 600;
248
    // If the starting element is within a table, the cell that contains it
mjs's avatar
mjs committed
249
    HTMLTableCellElement* startingTableCell = 0;
250 251
    bool searchedCellAbove = false;

trey's avatar
trey committed
252 253
    // walk backwards in the node tree, until another element, or form, or end of tree
    int unsigned lengthSearched = 0;
mjs's avatar
mjs committed
254
    Node* n;
trey's avatar
trey committed
255 256 257 258
    for (n = element->traversePreviousNode();
         n && lengthSearched < charsSearchedThreshold;
         n = n->traversePreviousNode())
    {
259
        if (n->hasTagName(formTag)
trey's avatar
trey committed
260
            || (n->isHTMLElement()
261
                && static_cast<HTMLElement*>(n)->isGenericFormElement()))
trey's avatar
trey committed
262 263 264
        {
            // We hit another form element or the start of the form - bail out
            break;
265
        } else if (n->hasTagName(tdTag) && !startingTableCell) {
266
            startingTableCell = static_cast<HTMLTableCellElement*>(n);
267
        } else if (n->hasTagName(trTag) && startingTableCell) {
mjs's avatar
mjs committed
268
            NSString* result = searchForLabelsAboveCell(regExp, startingTableCell);
sullivan's avatar
sullivan committed
269
            if (result && [result length] > 0)
270 271
                return result;
            searchedCellAbove = true;
272
        } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
trey's avatar
trey committed
273
            // For each text chunk, run the regexp
darin's avatar
darin committed
274
            DeprecatedString nodeString = n->nodeValue().deprecatedString();
trey's avatar
trey committed
275
            // add 100 for slop, to make it more likely that we'll search whole nodes
276
            if (lengthSearched + nodeString.length() > maxCharsSearched)
trey's avatar
trey committed
277 278
                nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
            int pos = regExp->searchRev(nodeString);
279
            if (pos >= 0)
trey's avatar
trey committed
280
                return nodeString.mid(pos, regExp->matchedLength()).getNSString();
sullivan's avatar
sullivan committed
281 282

            lengthSearched += nodeString.length();
trey's avatar
trey committed
283 284
        }
    }
285 286 287 288

    // If we started in a cell, but bailed because we found the start of the form or the
    // previous element, we still might need to search the row above us for a label.
    if (startingTableCell && !searchedCellAbove) {
sullivan's avatar
sullivan committed
289 290 291
        NSString* result = searchForLabelsAboveCell(regExp, startingTableCell);
        if (result && [result length] > 0)
            return result;
292
    }
sullivan's avatar
sullivan committed
293 294
    
    return nil;
trey's avatar
trey committed
295 296
}

mjs's avatar
mjs committed
297
NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
trey's avatar
trey committed
298
{
darin's avatar
darin committed
299
    DeprecatedString name = element->getAttribute(nameAttr).deprecatedString();
300
    // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
darin@apple.com's avatar
darin@apple.com committed
301
    name.replace(RegularExpression("\\d"), " ");
darin's avatar
darin committed
302
    name.replace('_', ' ');
303
    
mjs's avatar
mjs committed
304
    RegularExpression* regExp = regExpForLabels(labels);
trey's avatar
trey committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
    // Use the largest match we can find in the whole name string
    int pos;
    int length;
    int bestPos = -1;
    int bestLength = -1;
    int start = 0;
    do {
        pos = regExp->search(name, start);
        if (pos != -1) {
            length = regExp->matchedLength();
            if (length >= bestLength) {
                bestPos = pos;
                bestLength = length;
            }
            start = pos+1;
        }
    } while (pos != -1);

323
    if (bestPos != -1)
trey's avatar
trey committed
324
        return name.mid(bestPos, bestLength).getNSString();
darin's avatar
darin committed
325
    return nil;
trey's avatar
trey committed
326 327
}

mjs's avatar
mjs committed
328
NSImage* Frame::imageFromRect(NSRect rect) const
rjw's avatar
rjw committed
329
{
mjs's avatar
mjs committed
330
    NSView* view = d->m_view->getDocumentView();
331
    if (!view)
332
        return nil;
333 334
    if (![view respondsToSelector:@selector(drawSingleRect:)])
        return nil;
335
    
mjs's avatar
mjs committed
336
    NSImage* resultImage;
darin's avatar
darin committed
337
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
338
    
darin's avatar
darin committed
339
    NSRect bounds = [view bounds];
340 341 342 343 344 345 346
    
    // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
    rect = [view convertRect:rect toView:nil];
    rect.size.height = roundf(rect.size.height);
    rect.size.width = roundf(rect.size.width);
    rect = [view convertRect:rect fromView:nil];
    
justing's avatar
justing committed
347
    resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
darin's avatar
darin committed
348

darin's avatar
darin committed
349 350 351
    if (rect.size.width != 0 && rect.size.height != 0) {
        [resultImage setFlipped:YES];
        [resultImage lockFocus];
darin's avatar
darin committed
352 353 354
        CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
355 356 357 358 359 360

        // Note: Must not call drawRect: here, because drawRect: assumes that it's called from AppKit's
        // display machinery. It calls getRectsBeingDrawn:count:, which can only be called inside
        // when a real AppKit display is underway.
        [view drawSingleRect:rect];

darin's avatar
darin committed
361
        CGContextRestoreGState(context);
darin's avatar
darin committed
362 363 364
        [resultImage unlockFocus];
        [resultImage setFlipped:NO];
    }
darin's avatar
darin committed
365 366 367

    return resultImage;

darin's avatar
darin committed
368
    END_BLOCK_OBJC_EXCEPTIONS;
369
    
darin's avatar
darin committed
370
    return nil;
371 372
}

sullivan's avatar
sullivan committed
373
NSImage* Frame::selectionImage(bool forceBlackText) const
374
{
sullivan's avatar
sullivan committed
375
    d->m_paintRestriction = forceBlackText ? PaintRestrictionSelectionOnlyBlackText : PaintRestrictionSelectionOnly;
adele's avatar
adele committed
376 377
    d->m_doc->updateLayout();
    NSImage* result = imageFromRect(selectionRect());
378
    d->m_paintRestriction = PaintRestrictionNone;
379 380 381
    return result;
}

mjs's avatar
mjs committed
382
NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
383
{
mjs's avatar
mjs committed
384
    RenderObject* renderer = node->renderer();
385
    if (!renderer)
386 387
        return nil;
    
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;
trey's avatar
trey committed
392
    NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
393

394
    d->m_elementToDraw = node;              // invoke special sub-tree drawing mode
mjs's avatar
mjs committed
395
    NSImage* result = imageFromRect(paintingRect);
396
    renderer->updateDragState(false);
harrison's avatar
harrison committed
397
    d->m_doc->updateLayout();
398
    d->m_elementToDraw = 0;
399

400
    if (elementRect)
trey's avatar
trey committed
401
        *elementRect = topLevelRect;
402
    if (imageRect)
trey's avatar
trey committed
403
        *imageRect = paintingRect;
404 405 406
    return result;
}

mjs's avatar
mjs committed
407
NSDictionary* Frame::fontAttributesForSelectionStart() const
darin's avatar
darin committed
408
{
mjs's avatar
mjs committed
409 410
    Node* nodeToRemove;
    RenderStyle* style = styleForSelectionStart(nodeToRemove);
darin's avatar
darin committed
411 412 413
    if (!style)
        return nil;

mjs's avatar
mjs committed
414
    NSMutableDictionary* result = [NSMutableDictionary dictionary];
darin's avatar
darin committed
415 416

    if (style->backgroundColor().isValid() && style->backgroundColor().alpha() != 0)
eseidel's avatar
eseidel committed
417
        [result setObject:nsColor(style->backgroundColor()) forKey:NSBackgroundColorAttributeName];
darin's avatar
darin committed
418

darin's avatar
darin committed
419 420
    if (style->font().primaryFont()->getNSFont())
        [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
darin's avatar
darin committed
421

422
    if (style->color().isValid() && style->color() != Color::black)
eseidel's avatar
eseidel committed
423
        [result setObject:nsColor(style->color()) forKey:NSForegroundColorAttributeName];
darin's avatar
darin committed
424

mjs's avatar
mjs committed
425
    ShadowData* shadow = style->textShadow();
darin's avatar
darin committed
426
    if (shadow) {
mjs's avatar
mjs committed
427
        NSShadow* s = [[NSShadow alloc] init];
darin's avatar
darin committed
428 429
        [s setShadowOffset:NSMakeSize(shadow->x, shadow->y)];
        [s setShadowBlurRadius:shadow->blur];
eseidel's avatar
eseidel committed
430
        [s setShadowColor:nsColor(shadow->color)];
darin's avatar
darin committed
431 432 433 434
        [result setObject:s forKey:NSShadowAttributeName];
    }

    int decoration = style->textDecorationsInEffect();
darin's avatar
darin committed
435
    if (decoration & LINE_THROUGH)
darin's avatar
darin committed
436 437 438 439
        [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];

    int superscriptInt = 0;
    switch (style->verticalAlign()) {
darin's avatar
darin committed
440 441 442 443 444 445 446 447
        case BASELINE:
        case BOTTOM:
        case BASELINE_MIDDLE:
        case LENGTH:
        case MIDDLE:
        case TEXT_BOTTOM:
        case TEXT_TOP:
        case TOP:
darin's avatar
darin committed
448
            break;
darin's avatar
darin committed
449
        case SUB:
darin's avatar
darin committed
450 451
            superscriptInt = -1;
            break;
darin's avatar
darin committed
452
        case SUPER:
darin's avatar
darin committed
453 454 455 456 457 458
            superscriptInt = 1;
            break;
    }
    if (superscriptInt)
        [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];

darin's avatar
darin committed
459
    if (decoration & UNDERLINE)
darin's avatar
darin committed
460 461 462
        [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];

    if (nodeToRemove) {
darin's avatar
darin committed
463 464 465
        ExceptionCode ec = 0;
        nodeToRemove->remove(ec);
        ASSERT(ec == 0);
darin's avatar
darin committed
466 467 468 469 470
    }

    return result;
}

mjs's avatar
mjs committed
471
NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const
kocienda's avatar
kocienda committed
472 473 474
{
    NSWritingDirection result = NSWritingDirectionLeftToRight;

justing's avatar
justing committed
475
    Position pos = selectionController()->selection().visibleStart().deepEquivalent();
mjs's avatar
mjs committed
476
    Node* node = pos.node();
kocienda's avatar
kocienda committed
477 478
    if (!node || !node->renderer() || !node->renderer()->containingBlock())
        return result;
mjs's avatar
mjs committed
479
    RenderStyle* style = node->renderer()->containingBlock()->style();
kocienda's avatar
kocienda committed
480 481 482 483
    if (!style)
        return result;
        
    switch (style->direction()) {
darin's avatar
darin committed
484
        case LTR:
kocienda's avatar
kocienda committed
485 486
            result = NSWritingDirectionLeftToRight;
            break;
darin's avatar
darin committed
487
        case RTL:
kocienda's avatar
kocienda committed
488 489 490 491 492 493 494
            result = NSWritingDirectionRightToLeft;
            break;
    }

    return result;
}

mjs's avatar
mjs committed
495
void Frame::issuePasteCommand()
496
{
mjs's avatar
mjs committed
497
    [d->m_bridge issuePasteCommand];
498 499
}

adele's avatar
adele committed
500
const short enableRomanKeyboardsOnly = -23;
darin's avatar
darin committed
501
void Frame::setUseSecureKeyboardEntry(bool enable)
adele's avatar
adele committed
502
{
darin's avatar
darin committed
503 504
    if (enable == IsSecureEventInputEnabled())
        return;
adele's avatar
adele committed
505
    if (enable) {
adele's avatar
adele committed
506
        EnableSecureEventInput();
adele's avatar
adele committed
507
#ifdef BUILDING_ON_TIGER
adele's avatar
adele committed
508
        KeyScript(enableRomanKeyboardsOnly);
adele's avatar
adele committed
509 510 511 512
#else
        CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
        TSMSetDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag, sizeof(CFArrayRef), &inputSources);
        CFRelease(inputSources);
513
#endif
adele's avatar
adele committed
514
    } else {
adele's avatar
adele committed
515
        DisableSecureEventInput();
adele's avatar
adele committed
516
#ifdef BUILDING_ON_TIGER
adele's avatar
adele committed
517
        KeyScript(smKeyEnableKybds);
adele's avatar
adele committed
518 519
#else
        TSMRemoveDocumentProperty(TSMGetActiveDocument(), kTSMDocumentEnabledInputSourcesPropertyTag);
520
#endif
adele's avatar
adele committed
521
    }
adele's avatar
adele committed
522 523
}

mjs's avatar
mjs committed
524
NSMutableDictionary* Frame::dashboardRegionsDictionary()
rjw's avatar
rjw committed
525
{
mjs's avatar
mjs committed
526
    Document* doc = document();
527
    if (!doc)
rjw's avatar
rjw committed
528 529
        return nil;

darin's avatar
darin committed
530 531
    const Vector<DashboardRegionValue>& regions = doc->dashboardRegions();
    size_t n = regions.size();
rjw's avatar
rjw committed
532

andersca's avatar
andersca committed
533
    // Convert the Vector<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
mjs's avatar
mjs committed
534
    NSMutableDictionary* webRegions = [NSMutableDictionary dictionaryWithCapacity:n];
darin's avatar
darin committed
535 536
    for (size_t i = 0; i < n; i++) {
        const DashboardRegionValue& region = regions[i];
537 538 539

        if (region.type == StyleDashboardRegion::None)
            continue;
540 541
        
        NSString *label = region.label;
rjw's avatar
rjw committed
542
        WebDashboardRegionType type = WebDashboardRegionTypeNone;
darin's avatar
darin committed
543
        if (region.type == StyleDashboardRegion::Circle)
rjw's avatar
rjw committed
544
            type = WebDashboardRegionTypeCircle;
darin's avatar
darin committed
545
        else if (region.type == StyleDashboardRegion::Rectangle)
rjw's avatar
rjw committed
546 547 548
            type = WebDashboardRegionTypeRectangle;
        NSMutableArray *regionValues = [webRegions objectForKey:label];
        if (!regionValues) {
darin's avatar
darin committed
549
            regionValues = [[NSMutableArray alloc] initWithCapacity:1];
rjw's avatar
rjw committed
550
            [webRegions setObject:regionValues forKey:label];
darin's avatar
darin committed
551
            [regionValues release];
rjw's avatar
rjw committed
552 553
        }
        
darin's avatar
darin committed
554
        WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type];
rjw's avatar
rjw committed
555
        [regionValues addObject:webRegion];
darin's avatar
darin committed
556
        [webRegion release];
rjw's avatar
rjw committed
557 558
    }
    
rjw's avatar
rjw committed
559 560 561
    return webRegions;
}

mjs's avatar
mjs committed
562
void Frame::dashboardRegionsChanged()
rjw's avatar
rjw committed
563 564
{
    NSMutableDictionary *webRegions = dashboardRegionsDictionary();
mjs's avatar
mjs committed
565
    [d->m_bridge dashboardRegionsChanged:webRegions];
rjw's avatar
rjw committed
566
}
567

mjs's avatar
mjs committed
568
void Frame::willPopupMenu(NSMenu * menu)
adele's avatar
adele committed
569
{
mjs's avatar
mjs committed
570
    [d->m_bridge willPopupMenu:menu];
adele's avatar
adele committed
571 572
}

thatcher's avatar
thatcher committed
573
FloatRect Frame::customHighlightLineRect(const AtomicString& type, const FloatRect& lineRect, Node* node)
574
{
thatcher's avatar
thatcher committed
575
    return [d->m_bridge customHighlightRect:type forLine:lineRect representedNode:node];
hyatt's avatar
hyatt committed
576 577
}

thatcher's avatar
thatcher committed
578
void Frame::paintCustomHighlight(const AtomicString& type, const FloatRect& boxRect, const FloatRect& lineRect, bool text, bool line, Node* node)
hyatt's avatar
hyatt committed
579
{
thatcher's avatar
thatcher committed
580
    [d->m_bridge paintCustomHighlight:type forBox:boxRect onLine:lineRect behindText:text entireLine:line representedNode:node];
581
}
thatcher's avatar
thatcher committed
582

583 584 585 586
DragImageRef Frame::dragImageForSelection() 
{
    if (!selectionController()->isRange())
        return nil;
mjs's avatar
mjs committed
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
    return selectionImage();
}


KJS::Bindings::Instance* Frame::createScriptInstanceForWidget(WebCore::Widget* widget)
{
    NSView* aView = widget->getView();
    if (!aView)
        return 0;

    void* nativeHandle = aView;
    CreateRootObjectFunction createRootObject = RootObject::createRootObject();
    RefPtr<RootObject> rootObject = createRootObject(nativeHandle);

    if ([aView respondsToSelector:@selector(objectForWebScript)]) {
        id objectForWebScript = [aView objectForWebScript];
        if (objectForWebScript)
            return Instance::createBindingForLanguageInstance(Instance::ObjectiveCLanguage, objectForWebScript, rootObject.release());
        return 0;
    } else if ([aView respondsToSelector:@selector(createPluginScriptableObject)]) {
thatcher's avatar
thatcher committed
607
#if USE(NPOBJECT)
mjs's avatar
mjs committed
608 609 610 611 612 613 614 615
        NPObject* npObject = [aView createPluginScriptableObject];
        if (npObject) {
            Instance* instance = Instance::createBindingForLanguageInstance(Instance::CLanguage, npObject, rootObject.release());

            // -createPluginScriptableObject returns a retained NPObject.  The caller is expected to release it.
            _NPN_ReleaseObject(npObject);
            return instance;
        }
thatcher's avatar
thatcher committed
616
#endif
mjs's avatar
mjs committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
        return 0;
    }

    jobject applet;
    
    // Get a pointer to the actual Java applet instance.
    if ([d->m_bridge respondsToSelector:@selector(getAppletInView:)])
        applet = [d->m_bridge getAppletInView:aView];
    else
        applet = [d->m_bridge pollForAppletInView:aView];
    
    if (applet) {
        // Wrap the Java instance in a language neutral binding and hand
        // off ownership to the APPLET element.
        Instance* instance = Instance::createBindingForLanguageInstance(Instance::JavaLanguage, applet, rootObject.release());
        return instance;
    }
    
    return 0;
}

WebScriptObject* Frame::windowScriptObject()
{
ggaren's avatar
ggaren committed
640
    Settings* settings = this->settings();
thatcher's avatar
thatcher committed
641
    if (!settings || !settings->isJavaScriptEnabled())
mjs's avatar
mjs committed
642 643 644 645 646 647
        return 0;

    if (!d->m_windowScriptObject) {
        KJS::JSLock lock;
        KJS::JSObject* win = KJS::Window::retrieveWindow(this);
        KJS::Bindings::RootObject *root = bindingRootObject();
thatcher's avatar
thatcher committed
648
        d->m_windowScriptObject = [WebScriptObject scriptObjectForJSObject:toRef(win) originRootObject:root rootObject:root];
mjs's avatar
mjs committed
649 650
    }

thatcher's avatar
thatcher committed
651
    return d->m_windowScriptObject.get();
mjs's avatar
mjs committed
652 653
}

thatcher's avatar
thatcher committed
654
void Frame::clearPlatformScriptObjects()
mjs's avatar
mjs committed
655
{
thatcher's avatar
thatcher committed
656 657 658 659
    if (d->m_windowScriptObject) {
        KJS::Bindings::RootObject* root = bindingRootObject();
        [d->m_windowScriptObject.get() _setOriginRootObject:root andRootObject:root];
    }
660
}
661

ggaren's avatar
ggaren committed
662
} // namespace WebCore