📄 framemac.mm
字号:
/* * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * * 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. */#import "config.h"#import "Frame.h"#import "BlockExceptions.h"#import "ColorMac.h"#import "Cursor.h"#import "DOMInternal.h"#import "DocumentLoader.h"#import "EditorClient.h"#import "Event.h"#import "FrameLoaderClient.h"#import "FrameView.h"#import "GraphicsContext.h"#import "HTMLNames.h"#import "HTMLTableCellElement.h"#import "HitTestRequest.h"#import "HitTestResult.h"#import "KeyboardEvent.h"#import "Logging.h"#import "MouseEventWithHitTestResults.h"#import "Page.h"#import "PlatformKeyboardEvent.h"#import "PlatformWheelEvent.h"#import "RegularExpression.h"#import "RenderTableCell.h"#import "Scrollbar.h"#import "SimpleFontData.h"#import "UserStyleSheetLoader.h"#import "WebCoreViewFactory.h"#import "visible_units.h"#import <Carbon/Carbon.h>#import <runtime/JSLock.h>#import <wtf/StdLibExtras.h>#if ENABLE(DASHBOARD_SUPPORT)#import "WebDashboardRegion.h"#endif @interface NSView (WebCoreHTMLDocumentView)- (void)drawSingleRect:(NSRect)rect;@end using namespace std;using JSC::JSLock;namespace WebCore {using namespace HTMLNames;// Either get cached regexp or build one that matches any of the labels.// The regexp we build is of the form: (STR1|STR2|STRN)static RegularExpression* regExpForLabels(NSArray* labels){ // All the ObjC calls in this method are simple array and string // calls which we can assume do not raise exceptions // 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; static NSMutableArray* regExpLabels = nil; DEFINE_STATIC_LOCAL(Vector<RegularExpression*>, regExps, ()); DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive)); RegularExpression* result; if (!regExpLabels) regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize]; CFIndex cacheHit = [regExpLabels indexOfObject:labels]; if (cacheHit != NSNotFound) result = regExps.at(cacheHit); else { String pattern("("); unsigned int numLabels = [labels count]; unsigned int i; for (i = 0; i < numLabels; i++) { String label = [labels objectAtIndex:i]; bool startsWithWordChar = false; bool endsWithWordChar = false; if (label.length() != 0) { startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0; endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0; } if (i != 0) pattern.append("|"); // 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"); pattern.append(label); if (endsWithWordChar) pattern.append("\\b"); } pattern.append(")"); result = new RegularExpression(pattern, TextCaseInsensitive); } // 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]; RegularExpression* last = regExps.last(); regExps.removeLast(); delete last; } } return result;}NSString* Frame::searchForNSLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell){ RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer()); if (cellRenderer && cellRenderer->isTableCell()) { RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer); if (cellAboveRenderer) { HTMLTableCellElement* aboveCell = static_cast<HTMLTableCellElement*>(cellAboveRenderer->node()); if (aboveCell) { // search within the above cell we found for a match for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) { if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { // For each text chunk, run the regexp String nodeString = n->nodeValue(); int pos = regExp->searchRev(nodeString); if (pos >= 0) return nodeString.substring(pos, regExp->matchedLength()); } } } } } // Any reason in practice to search all cells in that are above cell? return nil;}NSString* Frame::searchForLabelsBeforeElement(NSArray* labels, Element* element){ RegularExpression* regExp = regExpForLabels(labels); // We stop searching after we've seen this many chars const unsigned int charsSearchedThreshold = 500; // 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. const unsigned int maxCharsSearched = 600; // If the starting element is within a table, the cell that contains it HTMLTableCellElement* startingTableCell = 0; bool searchedCellAbove = false; // walk backwards in the node tree, until another element, or form, or end of tree int unsigned lengthSearched = 0; Node* n; for (n = element->traversePreviousNode(); n && lengthSearched < charsSearchedThreshold; n = n->traversePreviousNode()) { if (n->hasTagName(formTag) || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())) { // We hit another form element or the start of the form - bail out break; } else if (n->hasTagName(tdTag) && !startingTableCell) { startingTableCell = static_cast<HTMLTableCellElement*>(n); } else if (n->hasTagName(trTag) && startingTableCell) { NSString* result = searchForLabelsAboveCell(regExp, startingTableCell); if (result && [result length] > 0) return result; searchedCellAbove = true; } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { // For each text chunk, run the regexp String nodeString = n->nodeValue(); // add 100 for slop, to make it more likely that we'll search whole nodes if (lengthSearched + nodeString.length() > maxCharsSearched) nodeString = nodeString.right(charsSearchedThreshold - lengthSearched); int pos = regExp->searchRev(nodeString); if (pos >= 0) return nodeString.substring(pos, regExp->matchedLength()); lengthSearched += nodeString.length(); } } // 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) { NSString* result = searchForLabelsAboveCell(regExp, startingTableCell); if (result && [result length] > 0) return result; } return nil;}NSString* Frame::matchLabelsAgainstElement(NSArray* labels, Element* element){ String name = element->getAttribute(nameAttr); if (name.isEmpty()) return nil; // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" replace(name, RegularExpression("\\d", TextCaseSensitive), " "); name.replace('_', ' '); RegularExpression* regExp = regExpForLabels(labels); // 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->match(name, start); if (pos != -1) { length = regExp->matchedLength(); if (length >= bestLength) { bestPos = pos; bestLength = length; } start = pos + 1; } } while (pos != -1); if (bestPos != -1) return name.substring(bestPos, bestLength); return nil;}NSImage* Frame::imageFromRect(NSRect rect) const{ NSView* view = m_view->documentView(); if (!view) return nil; if (![view respondsToSelector:@selector(drawSingleRect:)]) return nil;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -