Changeset 37863 in webkit
- Timestamp:
- Oct 24, 2008, 2:12:45 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r37858 r37863 1 2008-10-24 Adele Peterson <adele@apple.com> 2 3 Reviewed by Sam Weinig. 4 5 WebCore part of fix for <rdar://problem/5839256> FILE CONTROL: multi-file upload. 6 7 This change adds support for multiple file selection in an <input type="file"> control when the "multiple" attribute is used. 8 This is consistent with the direction HTML5 will be going in the future. 9 10 The initial implementation here will show "n files" as the text next to the control when multiple files are selected. You can view 11 the individual files in a tooltip for now. Improvements to this control will come later. 12 13 Web developers will be able to access the FileList from the HTMLInputElement element, where they can get a base name and a size for each file. 14 These FileList Files can also be sent in an XMLHTTPRequest. 15 16 * manual-tests/post-multi-file-upload.html: Added. 17 * manual-tests/resources/multiFileResources: Added. 18 * manual-tests/resources/multiFileResources/post-echo-and-notify-done.cgi: Added. 19 * manual-tests/resources/multiFileResources/testFile1.html: Added. 20 * manual-tests/resources/multiFileResources/testFile2.html: Added. 21 * manual-tests/resources/multiFileResources/testFile3.html: Added. 22 23 * WebCore.base.exp: Added support to export the new "chooseFilenames" method to be used in WebKit. 24 25 * html/HTMLInputElement.cpp: 26 (WebCore::HTMLInputElement::parseMappedAttribute): Add support for the multiple attribute. 27 (WebCore::HTMLInputElement::value): Added comments. The HTML5 spec says that value shouldn't apply for the file upload control, 28 but we don't want to break the behavior for existing websites that may rely on this. 29 (WebCore::HTMLInputElement::setValue): ditto. 30 (WebCore::HTMLInputElement::setValueFromRenderer): This is no longer used for file upload controls. setFileListFromRenderer is used instead. 31 (WebCore::HTMLInputElement::setFileListFromRenderer): Added. 32 * html/HTMLInputElement.h: 33 34 * page/Chrome.cpp: (WebCore::Chrome::setToolTip): Show a tooltip with the file name list for the multi-file upload control. 35 36 * page/DragController.cpp: (WebCore::DragController::concludeDrag): Updated to support multiple files. 37 38 * platform/FileChooser.cpp: Add support for maintaining a list of file paths that can be retrieved by the renderer. 39 (WebCore::FileChooser::FileChooser): 40 (WebCore::FileChooser::create): 41 (WebCore::FileChooser::clear): 42 (WebCore::FileChooser::chooseFile): 43 (WebCore::FileChooser::chooseFiles): 44 (WebCore::FileChooser::chooseIcon): 45 * platform/FileChooser.h: 46 (WebCore::FileChooser::filePaths): 47 (WebCore::FileChooser::allowsMultipleFiles): 48 49 * platform/graphics/Icon.h: 50 * platform/graphics/mac/IconMac.mm: (WebCore::Icon::newIconForFiles): Returns a generic icon for multiple files. 51 * platform/graphics/gtk/IconGtk.cpp: (WebCore::Icon::newIconForFiles): stubbed out. 52 * platform/graphics/qt/IconQt.cpp: (WebCore::Icon::newIconForFiles): ditto. 53 * platform/graphics/win/IconWin.cpp: (WebCore::Icon::newIconForFiles): ditto. 54 55 * platform/gtk/FileChooserGtk.cpp: (WebCore::FileChooser::basenameForWidth): Updated to deal with new filenames vector. 56 * platform/mac/FileChooserMac.mm: (WebCore::FileChooser::basenameForWidth): ditto. 57 * platform/qt/FileChooserQt.cpp: 58 (WebCore::FileChooser::openFileChooser): 59 (WebCore::FileChooser::basenameForWidth): 60 * platform/win/FileChooserWin.cpp: (WebCore::FileChooser::basenameForWidth): 61 62 * platform/network/mac/FormDataStreamMac.mm: (WebCore::disassociateStreamWithResourceHandle): 63 Removed unnecessary assertion. This can get hit when connectionDidFinishLoading and cancel 64 both get called for the same ResourceHandle. This getting called twice has no negative effect. 65 66 * rendering/RenderFileUploadControl.cpp: 67 (WebCore::RenderFileUploadControl::valueChanged): Calls setFileListFromRenderer. 68 (WebCore::RenderFileUploadControl::allowsMultipleFiles): Added. 69 (WebCore::RenderFileUploadControl::updateFromElement): Uses the new filenames call from FileChooser. 70 (WebCore::RenderFileUploadControl::receiveDroppedFiles): Updated to support multiple files. 71 * rendering/RenderFileUploadControl.h: 72 1 73 2008-10-23 Peter Kasting <pkasting@google.com> 2 74 -
trunk/WebCore/WebCore.base.exp
r37848 r37863 140 140 __ZN7WebCore11EditCommand7unapplyEv 141 141 __ZN7WebCore11FileChooser10chooseFileERKNS_6StringE 142 __ZN7WebCore11FileChooser11chooseFilesERKN3WTF6VectorINS_6StringELm0EEE 142 143 __ZN7WebCore11FileChooserD1Ev 143 144 __ZN7WebCore11FrameLoader11completeURLERKNS_6StringE … … 875 876 __ZNK7WebCore9TimerBase8isActiveEv 876 877 __ZTVN7WebCore12ChromeClientE 878 __ZTVN7WebCore17FileChooserClientE 877 879 _filenameByFixingIllegalCharacters 878 880 _hasCaseInsensitiveSubstring -
trunk/WebCore/html/HTMLInputElement.cpp
r37589 r37863 699 699 attr->name() == minAttr || 700 700 attr->name() == maxAttr || 701 attr->name() == precisionAttr) { 701 attr->name() == multipleAttr || 702 attr->name() == precisionAttr) 702 703 setChanged(); 703 }else704 else 704 705 HTMLFormControlElementWithState::parseMappedAttribute(attr); 705 706 } … … 951 952 String HTMLInputElement::value() const 952 953 { 954 // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control 955 // but we don't want to break existing websites, who may be relying on being able to get the file name as a value. 953 956 if (inputType() == FILE) { 954 957 if (!m_fileList->isEmpty()) … … 1000 1003 { 1001 1004 // For security reasons, we don't allow setting the filename, but we do allow clearing it. 1005 // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control 1006 // but we don't want to break existing websites, who may be relying on this method to clear things. 1002 1007 if (inputType() == FILE && !value.isEmpty()) 1003 1008 return; … … 1037 1042 ASSERT(value == constrainValue(value) || constrainValue(value).isEmpty()); 1038 1043 1044 // File upload controls will always use setFileListFromRenderer. 1045 ASSERT (inputType() != FILE); 1046 1039 1047 if (isTextField()) 1040 1048 updatePlaceholderVisibility(); 1041 1049 1042 if (inputType() == FILE) { 1043 m_fileList->clear(); 1044 m_fileList->append(File::create(value)); 1045 } else { 1046 // Workaround for bug where trailing \n is included in the result of textContent. 1047 // The assert macro above may also be simplified to: value == constrainValue(value) 1048 // http://bugs.webkit.org/show_bug.cgi?id=9661 1049 if (value == "\n") 1050 m_value = ""; 1051 else 1052 m_value = value; 1053 } 1050 // Workaround for bug where trailing \n is included in the result of textContent. 1051 // The assert macro above may also be simplified to: value == constrainValue(value) 1052 // http://bugs.webkit.org/show_bug.cgi?id=9661 1053 if (value == "\n") 1054 m_value = ""; 1055 else 1056 m_value = value; 1054 1057 1055 1058 setValueMatchesRenderer(); … … 1057 1060 // Fire the "input" DOM event. 1058 1061 dispatchEventForType(inputEvent, true, false); 1062 } 1063 1064 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) 1065 { 1066 m_fileList->clear(); 1067 int size = paths.size(); 1068 for (int i = 0; i < size; i++) 1069 m_fileList->append(File::create(paths[i])); 1070 1071 setValueMatchesRenderer(); 1059 1072 } 1060 1073 -
trunk/WebCore/html/HTMLInputElement.h
r37793 r37863 109 109 110 110 void setValueFromRenderer(const String&); 111 void setFileListFromRenderer(const Vector<String>&); 111 112 112 113 virtual bool saveState(String& value) const; -
trunk/WebCore/page/Chrome.cpp
r37628 r37863 25 25 #include "DNS.h" 26 26 #include "Document.h" 27 #include "FileList.h" 27 28 #include "FloatRect.h" 28 29 #include "Frame.h" … … 351 352 } 352 353 353 // Lastlywe'll consider a tooltip for element with "title" attribute354 // Next we'll consider a tooltip for element with "title" attribute 354 355 if (toolTip.isEmpty()) 355 356 toolTip = result.title(); 356 357 358 // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames 359 if (toolTip.isEmpty()) { 360 if (Node* node = result.innerNonSharedNode()) { 361 if (node->hasTagName(inputTag)) { 362 HTMLInputElement* input = static_cast<HTMLInputElement*>(node); 363 if (input->inputType() == HTMLInputElement::FILE) { 364 FileList* files = input->files(); 365 unsigned listSize = files->length(); 366 if (files && listSize > 1) { 367 Vector<UChar> names; 368 for (size_t i = 0; i < listSize; ++i) { 369 append(names, files->item(i)->fileName()); 370 if (i != listSize - 1) 371 names.append('\n'); 372 } 373 toolTip = String::adopt(names); 374 } 375 } 376 } 377 } 378 } 379 357 380 m_client->setToolTip(toolTip); 358 381 } -
trunk/WebCore/page/DragController.cpp
r37534 r37863 381 381 return false; 382 382 383 // Only take the first filename as <input type="file" /> can only accept one 384 renderer->receiveDroppedFile(filenames[0]); 383 renderer->receiveDroppedFiles(filenames); 385 384 return true; 386 385 } -
trunk/WebCore/platform/FileChooser.cpp
r30875 r37863 36 36 inline FileChooser::FileChooser(FileChooserClient* client, const String& filename) 37 37 : m_client(client) 38 , m_filename(filename)39 38 , m_icon(chooseIcon(filename)) 40 39 { 40 m_filenames.append(filename); 41 41 } 42 42 … … 52 52 void FileChooser::clear() 53 53 { 54 m_filename = String();55 m_icon = chooseIcon(m_filename);54 m_filenames.clear(); 55 m_icon = 0; 56 56 } 57 57 58 58 void FileChooser::chooseFile(const String& filename) 59 59 { 60 if (m_filename == filename)60 if (m_filenames.size() == 1 && m_filenames[0] == filename) 61 61 return; 62 m_filename = filename; 62 m_filenames.clear(); 63 m_filenames.append(filename); 63 64 m_icon = chooseIcon(filename); 65 if (m_client) 66 m_client->valueChanged(); 67 } 68 69 void FileChooser::chooseFiles(const Vector<String>& filenames) 70 { 71 m_filenames = filenames; 72 m_icon = chooseIcon(filenames); 64 73 if (m_client) 65 74 m_client->valueChanged(); … … 71 80 } 72 81 82 PassRefPtr<Icon> FileChooser::chooseIcon(Vector<String> filenames) 83 { 84 if (filenames.size() == 1) 85 return Icon::newIconForFile(filenames[0]); 86 return Icon::newIconForFiles(filenames); 73 87 } 88 89 } -
trunk/WebCore/platform/FileChooser.h
r30875 r37863 32 32 33 33 #include "PlatformString.h" 34 #include <wtf/Vector.h> 34 35 35 36 namespace WebCore { … … 43 44 virtual ~FileChooserClient() { } 44 45 virtual void valueChanged() = 0; 46 virtual bool allowsMultipleFiles() = 0; 45 47 }; 46 48 … … 60 62 void openFileChooser(Document*); 61 63 62 const String& filename() const { return m_filename; }64 const Vector<String>& filenames() const { return m_filenames; } 63 65 String basenameForWidth(const Font&, int width) const; 64 66 … … 67 69 void clear(); // for use by client; does not call valueChanged 68 70 69 void chooseFile(const String& filename); 71 void chooseFile(const String& path); 72 void chooseFiles(const Vector<String>& paths); 73 74 bool allowsMultipleFiles() const { return m_client ? m_client->allowsMultipleFiles() : false; } 70 75 71 76 private: 72 FileChooser(FileChooserClient*, const String& initial Filename);77 FileChooser(FileChooserClient*, const String& initialfilename); 73 78 static PassRefPtr<Icon> chooseIcon(const String& filename); 79 static PassRefPtr<Icon> chooseIcon(Vector<String> filenames); 74 80 75 81 FileChooserClient* m_client; 76 String m_filename;82 Vector<String> m_filenames; 77 83 RefPtr<Icon> m_icon; 78 84 }; -
trunk/WebCore/platform/graphics/Icon.h
r37776 r37863 25 25 #include <wtf/RefCounted.h> 26 26 #include <wtf/Forward.h> 27 #include <wtf/Vector.h> 27 28 28 29 #if PLATFORM(MAC) … … 52 53 public: 53 54 static PassRefPtr<Icon> newIconForFile(const String& filename); 55 static PassRefPtr<Icon> newIconForFiles(const Vector<String>& filenames); 56 54 57 ~Icon(); 55 58 -
trunk/WebCore/platform/graphics/gtk/IconGtk.cpp
r37679 r37863 104 104 } 105 105 106 PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames) 107 { 108 //FIXME: Implement this 109 return 0; 110 } 111 106 112 void Icon::paint(GraphicsContext* context, const IntRect& rect) 107 113 { -
trunk/WebCore/platform/graphics/mac/IconMac.mm
r34544 r37863 54 54 } 55 55 56 PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames) 57 { 58 if (filenames.isEmpty()) 59 return 0; 60 61 NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments]; 62 if (!image) 63 return 0; 64 65 return adoptRef(new Icon(image)); 66 } 67 56 68 void Icon::paint(GraphicsContext* context, const IntRect& rect) 57 69 { -
trunk/WebCore/platform/graphics/qt/IconQt.cpp
r34544 r37863 49 49 } 50 50 51 PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames) 52 { 53 //FIXME: Implement this 54 return 0; 55 } 56 51 57 void Icon::paint(GraphicsContext* ctx, const IntRect& rect) 52 58 { -
trunk/WebCore/platform/graphics/win/IconWin.cpp
r34544 r37863 51 51 } 52 52 53 PassRefPtr<Icon> Icon::newIconForFiles(const Vector<String>& filenames) 54 { 55 //FIXME: Implement this 56 return 0; 57 } 58 53 59 void Icon::paint(GraphicsContext* context, const IntRect& r) 54 60 { -
trunk/WebCore/platform/gtk/FileChooserGtk.cpp
r37610 r37863 85 85 String string = fileButtonNoFileSelectedLabel(); 86 86 87 if ( !m_filename.isEmpty()) {88 gchar* systemFilename = filenameFromString(m_filename );87 if (m_filenames.size() == 1) { 88 gchar* systemFilename = filenameFromString(m_filenames[0]); 89 89 gchar* systemBasename = g_path_get_basename(systemFilename); 90 90 g_free(systemFilename); 91 91 stringByAdoptingFileSystemRepresentation(systemBasename, string); 92 } 92 } else if (m_filenames.size() > 1) 93 return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false); 93 94 94 95 return StringTruncator::centerTruncate(string, width, font, false); -
trunk/WebCore/platform/mac/FileChooserMac.mm
r30875 r37863 59 59 60 60 String strToTruncate; 61 if (m_filename .isEmpty())61 if (m_filenames.isEmpty()) 62 62 strToTruncate = fileButtonNoFileSelectedLabel(); 63 else if (m_filenames.size() == 1) 64 strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:(m_filenames[0])]; 63 65 else 64 strToTruncate = [[NSFileManager defaultManager] displayNameAtPath:m_filename];66 return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false); 65 67 66 68 return StringTruncator::centerTruncate(strToTruncate, width, font, false); -
trunk/WebCore/platform/network/mac/FormDataStreamMac.mm
r37616 r37863 84 84 return; 85 85 86 ASSERT(getStreamResourceHandleMap().contains((CFReadStreamRef)stream));87 86 getStreamResourceHandleMap().remove((CFReadStreamRef)stream); 88 87 } -
trunk/WebCore/platform/qt/FileChooserQt.cpp
r30875 r37863 43 43 return; 44 44 45 QString f = fl->chooseFile(m_filename );45 QString f = fl->chooseFile(m_filenames[0]); 46 46 if (!f.isEmpty()) 47 47 chooseFile(f); … … 51 51 { 52 52 QFontMetrics fm(f.font()); 53 return fm.elidedText(m_filename , Qt::ElideLeft, width);53 return fm.elidedText(m_filenames[0], Qt::ElideLeft, width); 54 54 } 55 55 -
trunk/WebCore/platform/win/FileChooserWin.cpp
r37276 r37863 81 81 82 82 String string; 83 if (m_filename .isEmpty())83 if (m_filenames.isEmpty()) 84 84 string = fileButtonNoFileSelectedLabel(); 85 else {86 String tmpFilename = m_filename ;85 else if (m_filenames.size() == 1) { 86 String tmpFilename = m_filenames[0]; 87 87 LPTSTR basename = PathFindFileName(tmpFilename.charactersWithNullTermination()); 88 88 string = String(basename); 89 } 89 } else 90 return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false); 90 91 91 92 return StringTruncator::centerTruncate(string, width, font, false); -
trunk/WebCore/rendering/RenderFileUploadControl.cpp
r37637 r37863 22 22 #include "RenderFileUploadControl.h" 23 23 24 #include "FileList.h" 24 25 #include "FrameView.h" 25 26 #include "GraphicsContext.h" … … 87 88 88 89 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node()); 89 inputElement->set ValueFromRenderer(fileChooser->filename());90 inputElement->setFileListFromRenderer(fileChooser->filenames()); 90 91 inputElement->onChange(); 91 92 … … 95 96 } 96 97 98 bool RenderFileUploadControl::allowsMultipleFiles() 99 { 100 HTMLInputElement* input = static_cast<HTMLInputElement*>(node()); 101 return !input->getAttribute(multipleAttr).isNull(); 102 } 103 97 104 void RenderFileUploadControl::click() 98 105 { … … 103 110 { 104 111 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node()); 105 112 ASSERT(inputElement->inputType() == HTMLInputElement::FILE); 113 106 114 if (!m_button) { 107 115 m_button = new HTMLFileUploadInnerButtonElement(document(), inputElement); … … 121 129 m_button->setDisabled(!theme()->isEnabled(this)); 122 130 123 // This only supports clearing out the file name, but that's OK because for131 // This only supports clearing out the files, but that's OK because for 124 132 // security reasons that's the only change the DOM is allowed to make. 125 if (inputElement->value().isEmpty() && !m_fileChooser->filename().isEmpty()) { 133 FileList* files = inputElement->files(); 134 ASSERT(files); 135 if (files && files->isEmpty() && !m_fileChooser->filenames().isEmpty()) { 126 136 m_fileChooser->clear(); 127 137 repaint(); … … 252 262 } 253 263 254 void RenderFileUploadControl::receiveDroppedFile(const String& filename) 255 { 256 m_fileChooser->chooseFile(filename); 264 void RenderFileUploadControl::receiveDroppedFiles(const Vector<String>& paths) 265 { 266 if (allowsMultipleFiles()) 267 m_fileChooser->chooseFiles(paths); 268 else 269 m_fileChooser->chooseFile(paths[0]); 257 270 } 258 271 -
trunk/WebCore/rendering/RenderFileUploadControl.h
r37637 r37863 48 48 void valueChanged(); 49 49 50 void receiveDroppedFile (const String&);50 void receiveDroppedFiles(const Vector<String>&); 51 51 52 52 String buttonValue(); 53 53 String fileTextValue(); 54 55 bool allowsMultipleFiles(); 54 56 55 57 protected: -
trunk/WebKit/mac/ChangeLog
r37848 r37863 1 2008-10-24 Adele Peterson <adele@apple.com> 2 3 Reviewed by Sam Weinig. 4 5 WebKit part of fix for <rdar://problem/5839256> FILE CONTROL: multi-file upload. 6 7 * WebCoreSupport/WebChromeClient.mm: 8 (WebChromeClient::runOpenPanel): 9 (-[WebOpenPanelResultListener chooseFilenames:]): 10 * WebView/WebUIDelegate.h: 11 1 12 2008-10-24 Timothy Hatcher <timothy@apple.com> 2 13 -
trunk/WebKit/mac/WebCoreSupport/WebChromeClient.mm
r37371 r37863 59 59 #import <WebCore/WindowFeatures.h> 60 60 #import <wtf/PassRefPtr.h> 61 #import <wtf/Vector.h> 61 62 62 63 @interface NSView (WebNSViewDetails) … … 547 548 { 548 549 BEGIN_BLOCK_OBJC_EXCEPTIONS; 550 BOOL allowMultipleFiles = chooser->allowsMultipleFiles(); 549 551 WebOpenPanelResultListener *listener = [[WebOpenPanelResultListener alloc] initWithChooser:chooser]; 550 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener); 552 id delegate = [m_webView UIDelegate]; 553 if ([delegate respondsToSelector:@selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:)]) 554 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), listener, allowMultipleFiles); 555 else 556 CallUIDelegate(m_webView, @selector(webView:runOpenPanelForFileButtonWithResultListener:), listener); 551 557 [listener release]; 552 558 END_BLOCK_OBJC_EXCEPTIONS; … … 659 665 } 660 666 667 - (void)chooseFilenames:(NSArray *)filenames 668 { 669 ASSERT(_chooser); 670 if (!_chooser) 671 return; 672 int count = [filenames count]; 673 Vector<String> names(count); 674 for (int i = 0; i < count; i++) 675 names[i] = [filenames objectAtIndex:i]; 676 _chooser->chooseFiles(names); 677 _chooser->deref(); 678 _chooser = 0; 679 } 680 661 681 @end -
trunk/WebKit/mac/WebView/WebUIDelegate.h
r37474 r37863 130 130 131 131 /*! 132 @method chooseFilenames: 133 @abstract Call this method to return an array of filenames from the file open panel. 134 @param fileNames 135 */ 136 - (void)chooseFilenames:(NSArray *)fileNames AVAILABLE_AFTER_WEBKIT_VERSION_3_1; 137 138 /*! 132 139 @method cancel 133 140 @abstract Call this method to indicate that the file open panel was cancelled. … … 403 410 */ 404 411 - (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener; 412 413 /*! 414 @method webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles 415 @abstract Display a file open panel for a file input control that may allow multiple files to be selected. 416 @param sender The WebView sending the delegate method. 417 @param resultListener The object to call back with the results. 418 @param allowMultipleFiles YES if the open panel should allow myltiple files to be selected, NO if not. 419 @discussion This method is passed a callback object instead of giving a return 420 value so that it can be handled with a sheet. 421 */ 422 - (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener allowMultipleFiles:(BOOL)allowMultipleFiles WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_AFTER_WEBKIT_VERSION_3_1); 405 423 406 424 /*!
Note:
See TracChangeset
for help on using the changeset viewer.