|
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 |