WebCore/page/mac/FrameMac.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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) 2008 Nokia Corporation and/or its subsidiary(-ies)
       
     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 "BlockExceptions.h"
       
    32 #import "ColorMac.h"
       
    33 #import "Cursor.h"
       
    34 #import "DOMInternal.h"
       
    35 #import "DocumentLoader.h"
       
    36 #import "EditorClient.h"
       
    37 #import "Event.h"
       
    38 #import "FrameLoaderClient.h"
       
    39 #import "FrameView.h"
       
    40 #import "GraphicsContext.h"
       
    41 #import "HTMLNames.h"
       
    42 #import "HTMLTableCellElement.h"
       
    43 #import "HitTestRequest.h"
       
    44 #import "HitTestResult.h"
       
    45 #import "KeyboardEvent.h"
       
    46 #import "Logging.h"
       
    47 #import "MouseEventWithHitTestResults.h"
       
    48 #import "Page.h"
       
    49 #import "PlatformKeyboardEvent.h"
       
    50 #import "PlatformWheelEvent.h"
       
    51 #import "RegularExpression.h"
       
    52 #import "RenderTableCell.h"
       
    53 #import "Scrollbar.h"
       
    54 #import "SimpleFontData.h"
       
    55 #import "WebCoreViewFactory.h"
       
    56 #import "visible_units.h"
       
    57 
       
    58 #import <Carbon/Carbon.h>
       
    59 #import <wtf/StdLibExtras.h>
       
    60 
       
    61 #if ENABLE(DASHBOARD_SUPPORT)
       
    62 #import "WebDashboardRegion.h"
       
    63 #endif
       
    64  
       
    65 @interface NSView (WebCoreHTMLDocumentView)
       
    66 - (void)drawSingleRect:(NSRect)rect;
       
    67 @end
       
    68  
       
    69 using namespace std;
       
    70 
       
    71 namespace WebCore {
       
    72 
       
    73 using namespace HTMLNames;
       
    74 
       
    75 // Either get cached regexp or build one that matches any of the labels.
       
    76 // The regexp we build is of the form:  (STR1|STR2|STRN)
       
    77 static RegularExpression* regExpForLabels(NSArray* labels)
       
    78 {
       
    79     // All the ObjC calls in this method are simple array and string
       
    80     // calls which we can assume do not raise exceptions
       
    81 
       
    82 
       
    83     // Parallel arrays that we use to cache regExps.  In practice the number of expressions
       
    84     // that the app will use is equal to the number of locales is used in searching.
       
    85     static const unsigned int regExpCacheSize = 4;
       
    86     static NSMutableArray* regExpLabels = nil;
       
    87     DEFINE_STATIC_LOCAL(Vector<RegularExpression*>, regExps, ());
       
    88     DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
       
    89 
       
    90     RegularExpression* result;
       
    91     if (!regExpLabels)
       
    92         regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
       
    93     CFIndex cacheHit = [regExpLabels indexOfObject:labels];
       
    94     if (cacheHit != NSNotFound)
       
    95         result = regExps.at(cacheHit);
       
    96     else {
       
    97         String pattern("(");
       
    98         unsigned int numLabels = [labels count];
       
    99         unsigned int i;
       
   100         for (i = 0; i < numLabels; i++) {
       
   101             String label = [labels objectAtIndex:i];
       
   102 
       
   103             bool startsWithWordChar = false;
       
   104             bool endsWithWordChar = false;
       
   105             if (label.length() != 0) {
       
   106                 startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
       
   107                 endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
       
   108             }
       
   109             
       
   110             if (i != 0)
       
   111                 pattern.append("|");
       
   112             // Search for word boundaries only if label starts/ends with "word characters".
       
   113             // If we always searched for word boundaries, this wouldn't work for languages
       
   114             // such as Japanese.
       
   115             if (startsWithWordChar)
       
   116                 pattern.append("\\b");
       
   117             pattern.append(label);
       
   118             if (endsWithWordChar)
       
   119                 pattern.append("\\b");
       
   120         }
       
   121         pattern.append(")");
       
   122         result = new RegularExpression(pattern, TextCaseInsensitive);
       
   123     }
       
   124 
       
   125     // add regexp to the cache, making sure it is at the front for LRU ordering
       
   126     if (cacheHit != 0) {
       
   127         if (cacheHit != NSNotFound) {
       
   128             // remove from old spot
       
   129             [regExpLabels removeObjectAtIndex:cacheHit];
       
   130             regExps.remove(cacheHit);
       
   131         }
       
   132         // add to start
       
   133         [regExpLabels insertObject:labels atIndex:0];
       
   134         regExps.insert(0, result);
       
   135         // trim if too big
       
   136         if ([regExpLabels count] > regExpCacheSize) {
       
   137             [regExpLabels removeObjectAtIndex:regExpCacheSize];
       
   138             RegularExpression* last = regExps.last();
       
   139             regExps.removeLast();
       
   140             delete last;
       
   141         }
       
   142     }
       
   143     return result;
       
   144 }
       
   145 
       
   146 NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
       
   147 {
       
   148     RenderObject* cellRenderer = cell->renderer();
       
   149 
       
   150     if (cellRenderer && cellRenderer->isTableCell()) {
       
   151         RenderTableCell* tableCellRenderer = toRenderTableCell(cellRenderer);
       
   152         RenderTableCell* cellAboveRenderer = tableCellRenderer->table()->cellAbove(tableCellRenderer);
       
   153 
       
   154         if (cellAboveRenderer) {
       
   155             HTMLTableCellElement* aboveCell =
       
   156                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->node());
       
   157 
       
   158             if (aboveCell) {
       
   159                 // search within the above cell we found for a match
       
   160                 size_t lengthSearched = 0;    
       
   161                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
       
   162                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
       
   163                         // For each text chunk, run the regexp
       
   164                         String nodeString = n->nodeValue();
       
   165                         int pos = regExp->searchRev(nodeString);
       
   166                         if (pos >= 0) {
       
   167                             if (resultDistanceFromStartOfCell)
       
   168                                 *resultDistanceFromStartOfCell = lengthSearched;
       
   169                             return nodeString.substring(pos, regExp->matchedLength());
       
   170                         }
       
   171                         lengthSearched += nodeString.length();
       
   172                     }
       
   173                 }
       
   174             }
       
   175         }
       
   176     }
       
   177     // Any reason in practice to search all cells in that are above cell?
       
   178     if (resultDistanceFromStartOfCell)
       
   179         *resultDistanceFromStartOfCell = notFound;
       
   180     return nil;
       
   181 }
       
   182 
       
   183 NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
       
   184 {
       
   185     RegularExpression* regExp = regExpForLabels(labels);
       
   186     // We stop searching after we've seen this many chars
       
   187     const unsigned int charsSearchedThreshold = 500;
       
   188     // This is the absolute max we search.  We allow a little more slop than
       
   189     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
       
   190     const unsigned int maxCharsSearched = 600;
       
   191     // If the starting element is within a table, the cell that contains it
       
   192     HTMLTableCellElement* startingTableCell = 0;
       
   193     bool searchedCellAbove = false;
       
   194     
       
   195     if (resultDistance)
       
   196         *resultDistance = notFound;
       
   197     if (resultIsInCellAbove)
       
   198         *resultIsInCellAbove = false;
       
   199 
       
   200     // walk backwards in the node tree, until another element, or form, or end of tree
       
   201     int unsigned lengthSearched = 0;
       
   202     Node* n;
       
   203     for (n = element->traversePreviousNode();
       
   204          n && lengthSearched < charsSearchedThreshold;
       
   205          n = n->traversePreviousNode())
       
   206     {
       
   207         if (n->hasTagName(formTag)
       
   208             || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
       
   209         {
       
   210             // We hit another form element or the start of the form - bail out
       
   211             break;
       
   212         } else if (n->hasTagName(tdTag) && !startingTableCell) {
       
   213             startingTableCell = static_cast<HTMLTableCellElement*>(n);
       
   214         } else if (n->hasTagName(trTag) && startingTableCell) {
       
   215             NSString* result = searchForLabelsAboveCell(regExp, startingTableCell, resultDistance);
       
   216             if (result && [result length] > 0) {
       
   217                 if (resultIsInCellAbove)
       
   218                     *resultIsInCellAbove = true;
       
   219                 return result;
       
   220             }
       
   221             searchedCellAbove = true;
       
   222         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
       
   223             // For each text chunk, run the regexp
       
   224             String nodeString = n->nodeValue();
       
   225             // add 100 for slop, to make it more likely that we'll search whole nodes
       
   226             if (lengthSearched + nodeString.length() > maxCharsSearched)
       
   227                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
       
   228             int pos = regExp->searchRev(nodeString);
       
   229             if (pos >= 0) {
       
   230                 if (resultDistance)
       
   231                     *resultDistance = lengthSearched;
       
   232                 return nodeString.substring(pos, regExp->matchedLength());
       
   233             }
       
   234             lengthSearched += nodeString.length();
       
   235         }
       
   236     }
       
   237 
       
   238     // If we started in a cell, but bailed because we found the start of the form or the
       
   239     // previous element, we still might need to search the row above us for a label.
       
   240     if (startingTableCell && !searchedCellAbove) {
       
   241         NSString* result = searchForLabelsAboveCell(regExp, startingTableCell, resultDistance);
       
   242         if (result && [result length] > 0) {
       
   243             if (resultIsInCellAbove)
       
   244                 *resultIsInCellAbove = true;
       
   245             return result;
       
   246         }
       
   247     }
       
   248     
       
   249     return nil;
       
   250 }
       
   251 
       
   252 static NSString *matchLabelsAgainstString(NSArray *labels, const String& stringToMatch)
       
   253 {
       
   254     if (stringToMatch.isEmpty())
       
   255         return nil;
       
   256     
       
   257     String mutableStringToMatch = stringToMatch;
       
   258     
       
   259     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
       
   260     replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
       
   261     mutableStringToMatch.replace('_', ' ');
       
   262     
       
   263     RegularExpression* regExp = regExpForLabels(labels);
       
   264     // Use the largest match we can find in the whole string
       
   265     int pos;
       
   266     int length;
       
   267     int bestPos = -1;
       
   268     int bestLength = -1;
       
   269     int start = 0;
       
   270     do {
       
   271         pos = regExp->match(mutableStringToMatch, start);
       
   272         if (pos != -1) {
       
   273             length = regExp->matchedLength();
       
   274             if (length >= bestLength) {
       
   275                 bestPos = pos;
       
   276                 bestLength = length;
       
   277             }
       
   278             start = pos + 1;
       
   279         }
       
   280     } while (pos != -1);
       
   281     
       
   282     if (bestPos != -1)
       
   283         return mutableStringToMatch.substring(bestPos, bestLength);
       
   284     return nil;
       
   285 }
       
   286 
       
   287 NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element)
       
   288 {
       
   289     // Match against the name element, then against the id element if no match is found for the name element.
       
   290     // See 7538330 for one popular site that benefits from the id element check.
       
   291     // FIXME: This code is mirrored in Frame.cpp. It would be nice to make the Mac code call the platform-agnostic
       
   292     // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
       
   293     String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
       
   294     if (!resultFromNameAttribute.isEmpty())
       
   295         return resultFromNameAttribute;
       
   296     
       
   297     return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
       
   298 }
       
   299 
       
   300 NSImage* Frame::imageFromRect(NSRect rect) const
       
   301 {
       
   302     NSView* view = m_view->documentView();
       
   303     if (!view)
       
   304         return nil;
       
   305     if (![view respondsToSelector:@selector(drawSingleRect:)])
       
   306         return nil;
       
   307     
       
   308     PaintBehavior oldPaintBehavior = m_view->paintBehavior();
       
   309     m_view->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers);
       
   310 
       
   311     BEGIN_BLOCK_OBJC_EXCEPTIONS;
       
   312     
       
   313     NSRect bounds = [view bounds];
       
   314     
       
   315     // Round image rect size in window coordinate space to avoid pixel cracks at HiDPI (4622794)
       
   316     rect = [view convertRect:rect toView:nil];
       
   317     rect.size.height = roundf(rect.size.height);
       
   318     rect.size.width = roundf(rect.size.width);
       
   319     rect = [view convertRect:rect fromView:nil];
       
   320     
       
   321     NSImage* resultImage = [[[NSImage alloc] initWithSize:rect.size] autorelease];
       
   322 
       
   323     if (rect.size.width != 0 && rect.size.height != 0) {
       
   324         [resultImage setFlipped:YES];
       
   325         [resultImage lockFocus];
       
   326         CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
       
   327         CGContextSaveGState(context);
       
   328         CGContextTranslateCTM(context, bounds.origin.x - rect.origin.x, bounds.origin.y - rect.origin.y);
       
   329 
       
   330         // Note: Must not call drawRect: here, because drawRect: assumes that it's called from AppKit's
       
   331         // display machinery. It calls getRectsBeingDrawn:count:, which can only be called inside
       
   332         // when a real AppKit display is underway.
       
   333         [view drawSingleRect:rect];
       
   334 
       
   335         CGContextRestoreGState(context);
       
   336         [resultImage unlockFocus];
       
   337         [resultImage setFlipped:NO];
       
   338     }
       
   339 
       
   340     m_view->setPaintBehavior(oldPaintBehavior);
       
   341     return resultImage;
       
   342 
       
   343     END_BLOCK_OBJC_EXCEPTIONS;
       
   344     
       
   345     m_view->setPaintBehavior(oldPaintBehavior);
       
   346     return nil;
       
   347 }
       
   348 
       
   349 NSImage* Frame::selectionImage(bool forceBlackText) const
       
   350 {
       
   351     m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0));
       
   352     m_doc->updateLayout();
       
   353     NSImage* result = imageFromRect(selectionBounds());
       
   354     m_view->setPaintBehavior(PaintBehaviorNormal);
       
   355     return result;
       
   356 }
       
   357 
       
   358 NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
       
   359 {
       
   360     RenderObject* renderer = node->renderer();
       
   361     if (!renderer)
       
   362         return nil;
       
   363     
       
   364     renderer->updateDragState(true);    // mark dragged nodes (so they pick up the right CSS)
       
   365     m_doc->updateLayout();        // forces style recalc - needed since changing the drag state might
       
   366                                         // imply new styles, plus JS could have changed other things
       
   367     IntRect topLevelRect;
       
   368     NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
       
   369 
       
   370     m_view->setNodeToDraw(node);              // invoke special sub-tree drawing mode
       
   371     NSImage* result = imageFromRect(paintingRect);
       
   372     renderer->updateDragState(false);
       
   373     m_doc->updateLayout();
       
   374     m_view->setNodeToDraw(0);
       
   375 
       
   376     if (elementRect)
       
   377         *elementRect = topLevelRect;
       
   378     if (imageRect)
       
   379         *imageRect = paintingRect;
       
   380     return result;
       
   381 }
       
   382 
       
   383 NSImage* Frame::nodeImage(Node* node) const
       
   384 {
       
   385     RenderObject* renderer = node->renderer();
       
   386     if (!renderer)
       
   387         return nil;
       
   388 
       
   389     m_doc->updateLayout(); // forces style recalc
       
   390 
       
   391     IntRect topLevelRect;
       
   392     NSRect paintingRect = renderer->paintingRootRect(topLevelRect);
       
   393 
       
   394     m_view->setNodeToDraw(node); // invoke special sub-tree drawing mode
       
   395     NSImage* result = imageFromRect(paintingRect);
       
   396     m_view->setNodeToDraw(0);
       
   397 
       
   398     return result;
       
   399 }
       
   400 
       
   401 NSDictionary* Frame::fontAttributesForSelectionStart() const
       
   402 {
       
   403     Node* nodeToRemove;
       
   404     RenderStyle* style = styleForSelectionStart(nodeToRemove);
       
   405     if (!style)
       
   406         return nil;
       
   407 
       
   408     NSMutableDictionary* result = [NSMutableDictionary dictionary];
       
   409 
       
   410     if (style->visitedDependentColor(CSSPropertyBackgroundColor).isValid() && style->visitedDependentColor(CSSPropertyBackgroundColor).alpha() != 0)
       
   411         [result setObject:nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)) forKey:NSBackgroundColorAttributeName];
       
   412 
       
   413     if (style->font().primaryFont()->getNSFont())
       
   414         [result setObject:style->font().primaryFont()->getNSFont() forKey:NSFontAttributeName];
       
   415 
       
   416     if (style->visitedDependentColor(CSSPropertyColor).isValid() && style->visitedDependentColor(CSSPropertyColor) != Color::black)
       
   417         [result setObject:nsColor(style->visitedDependentColor(CSSPropertyColor)) forKey:NSForegroundColorAttributeName];
       
   418 
       
   419     const ShadowData* shadow = style->textShadow();
       
   420     if (shadow) {
       
   421         NSShadow* s = [[NSShadow alloc] init];
       
   422         [s setShadowOffset:NSMakeSize(shadow->x(), shadow->y())];
       
   423         [s setShadowBlurRadius:shadow->blur()];
       
   424         [s setShadowColor:nsColor(shadow->color())];
       
   425         [result setObject:s forKey:NSShadowAttributeName];
       
   426     }
       
   427 
       
   428     int decoration = style->textDecorationsInEffect();
       
   429     if (decoration & LINE_THROUGH)
       
   430         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
       
   431 
       
   432     int superscriptInt = 0;
       
   433     switch (style->verticalAlign()) {
       
   434         case BASELINE:
       
   435         case BOTTOM:
       
   436         case BASELINE_MIDDLE:
       
   437         case LENGTH:
       
   438         case MIDDLE:
       
   439         case TEXT_BOTTOM:
       
   440         case TEXT_TOP:
       
   441         case TOP:
       
   442             break;
       
   443         case SUB:
       
   444             superscriptInt = -1;
       
   445             break;
       
   446         case SUPER:
       
   447             superscriptInt = 1;
       
   448             break;
       
   449     }
       
   450     if (superscriptInt)
       
   451         [result setObject:[NSNumber numberWithInt:superscriptInt] forKey:NSSuperscriptAttributeName];
       
   452 
       
   453     if (decoration & UNDERLINE)
       
   454         [result setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
       
   455 
       
   456     if (nodeToRemove) {
       
   457         ExceptionCode ec = 0;
       
   458         nodeToRemove->remove(ec);
       
   459         ASSERT(ec == 0);
       
   460     }
       
   461 
       
   462     return result;
       
   463 }
       
   464 
       
   465 NSWritingDirection Frame::baseWritingDirectionForSelectionStart() const
       
   466 {
       
   467     NSWritingDirection result = NSWritingDirectionLeftToRight;
       
   468 
       
   469     Position pos = selection()->selection().visibleStart().deepEquivalent();
       
   470     Node* node = pos.node();
       
   471     if (!node)
       
   472         return result;
       
   473 
       
   474     RenderObject* renderer = node->renderer();
       
   475     if (!renderer)
       
   476         return result;
       
   477 
       
   478     if (!renderer->isBlockFlow()) {
       
   479         renderer = renderer->containingBlock();
       
   480         if (!renderer)
       
   481             return result;
       
   482     }
       
   483 
       
   484     RenderStyle* style = renderer->style();
       
   485     if (!style)
       
   486         return result;
       
   487         
       
   488     switch (style->direction()) {
       
   489         case LTR:
       
   490             result = NSWritingDirectionLeftToRight;
       
   491             break;
       
   492         case RTL:
       
   493             result = NSWritingDirectionRightToLeft;
       
   494             break;
       
   495     }
       
   496 
       
   497     return result;
       
   498 }
       
   499 
       
   500 #if ENABLE(DASHBOARD_SUPPORT)
       
   501 NSMutableDictionary* Frame::dashboardRegionsDictionary()
       
   502 {
       
   503     Document* doc = document();
       
   504 
       
   505     const Vector<DashboardRegionValue>& regions = doc->dashboardRegions();
       
   506     size_t n = regions.size();
       
   507 
       
   508     // Convert the Vector<DashboardRegionValue> into a NSDictionary of WebDashboardRegions
       
   509     NSMutableDictionary* webRegions = [NSMutableDictionary dictionaryWithCapacity:n];
       
   510     for (size_t i = 0; i < n; i++) {
       
   511         const DashboardRegionValue& region = regions[i];
       
   512 
       
   513         if (region.type == StyleDashboardRegion::None)
       
   514             continue;
       
   515         
       
   516         NSString *label = region.label;
       
   517         WebDashboardRegionType type = WebDashboardRegionTypeNone;
       
   518         if (region.type == StyleDashboardRegion::Circle)
       
   519             type = WebDashboardRegionTypeCircle;
       
   520         else if (region.type == StyleDashboardRegion::Rectangle)
       
   521             type = WebDashboardRegionTypeRectangle;
       
   522         NSMutableArray *regionValues = [webRegions objectForKey:label];
       
   523         if (!regionValues) {
       
   524             regionValues = [[NSMutableArray alloc] initWithCapacity:1];
       
   525             [webRegions setObject:regionValues forKey:label];
       
   526             [regionValues release];
       
   527         }
       
   528         
       
   529         WebDashboardRegion *webRegion = [[WebDashboardRegion alloc] initWithRect:region.bounds clip:region.clip type:type];
       
   530         [regionValues addObject:webRegion];
       
   531         [webRegion release];
       
   532     }
       
   533     
       
   534     return webRegions;
       
   535 }
       
   536 #endif
       
   537 
       
   538 DragImageRef Frame::dragImageForSelection() 
       
   539 {
       
   540     if (!selection()->isRange())
       
   541         return nil;
       
   542     return selectionImage();
       
   543 }
       
   544 
       
   545 } // namespace WebCore