summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/qt/tests
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/qt/tests')
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/MIMESniffing.pro19
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/TestData.h984
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources.qrc23
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_atom+xml17
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_oggbin0 -> 382185 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_pdfbin0 -> 218882 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_postscript137
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_rdf+xml50
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_rss+xml45
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_x-gzipbin0 -> 268 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_x-rar-compressedbin0 -> 1478 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/application_zipbin0 -> 411 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/audio_x-wavebin0 -> 184320 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/image_bmpbin0 -> 46182 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/image_gifbin0 -> 245 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/image_jpegbin0 -> 10874 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/image_pngbin0 -> 850 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/image_vnd.microsoft.iconbin0 -> 9662 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/image_webpbin0 -> 10474 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/text_html3
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/text_xml19
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/resources/video_webmbin0 -> 388027 bytes
-rw-r--r--Source/WebKit/qt/tests/MIMESniffing/tst_MIMESniffing.cpp72
-rw-r--r--Source/WebKit/qt/tests/benchmarks/loading/loading.pro3
-rw-r--r--Source/WebKit/qt/tests/benchmarks/loading/tst_loading.cpp105
-rw-r--r--Source/WebKit/qt/tests/benchmarks/painting/painting.pro3
-rw-r--r--Source/WebKit/qt/tests/benchmarks/painting/tst_painting.cpp136
-rw-r--r--Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html59
-rw-r--r--Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp130
-rw-r--r--Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc5
-rw-r--r--Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro4
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/hybridPixmap.pro11
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/resources.qrc5
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/test.html65
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/tst_hybridPixmap.cpp52
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/widget.cpp119
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/widget.h72
-rw-r--r--Source/WebKit/qt/tests/hybridPixmap/widget.ui95
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/qdeclarativewebview.pro6
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.html17
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.pngbin0 -> 3961 bytes
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.qml5
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.html14
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.qml7
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.html12
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.pngbin0 -> 2377 bytes
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.html11
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.qml12
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/loadError.qml5
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.html16
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.qml34
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/propertychanges.qml34
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/sample.html6
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/sethtml.qml5
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewbackgroundcolor.qml10
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtest.qml24
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtestdefault.qml22
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp544
-rw-r--r--Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.qrc22
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro6
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/resources/56929.html8
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/resources/input_types.html8
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html45
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html46
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp602
-rw-r--r--Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc8
-rw-r--r--Source/WebKit/qt/tests/qwebelement/qwebelement.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebelement/resources/image.pngbin0 -> 14743 bytes
-rw-r--r--Source/WebKit/qt/tests/qwebelement/resources/style.css1
-rw-r--r--Source/WebKit/qt/tests/qwebelement/resources/style2.css1
-rw-r--r--Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp1043
-rw-r--r--Source/WebKit/qt/tests/qwebelement/tst_qwebelement.qrc7
-rw-r--r--Source/WebKit/qt/tests/qwebframe/qwebframe.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebframe/resources/image.pngbin0 -> 14743 bytes
-rw-r--r--Source/WebKit/qt/tests/qwebframe/resources/style.css1
-rw-r--r--Source/WebKit/qt/tests/qwebframe/resources/test1.html1
-rw-r--r--Source/WebKit/qt/tests/qwebframe/resources/test2.html1
-rw-r--r--Source/WebKit/qt/tests/qwebframe/resources/testiframe.html54
-rw-r--r--Source/WebKit/qt/tests/qwebframe/resources/testiframe2.html21
-rw-r--r--Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp3645
-rw-r--r--Source/WebKit/qt/tests/qwebframe/tst_qwebframe.qrc10
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/qwebhistory.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/resources/page1.html1
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/resources/page2.html1
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/resources/page3.html1
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/resources/page4.html1
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/resources/page5.html1
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/resources/page6.html1
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.cpp397
-rw-r--r--Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.qrc11
-rw-r--r--Source/WebKit/qt/tests/qwebhistoryinterface/qwebhistoryinterface.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebhistoryinterface/tst_qwebhistoryinterface.cpp96
-rw-r--r--Source/WebKit/qt/tests/qwebinspector/qwebinspector.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebinspector/tst_qwebinspector.cpp68
-rw-r--r--Source/WebKit/qt/tests/qwebpage/qwebpage.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/content.html6
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/frame_a.html2
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/frame_c.html1
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/framedindex.html4
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/iframe.html6
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/iframe2.html7
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/iframe3.html5
-rw-r--r--Source/WebKit/qt/tests/qwebpage/resources/index.html4
-rw-r--r--Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp2881
-rw-r--r--Source/WebKit/qt/tests/qwebpage/tst_qwebpage.qrc13
-rw-r--r--Source/WebKit/qt/tests/qwebplugindatabase/qwebplugindatabase.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebplugindatabase/tst_qwebplugindatabase.cpp437
-rw-r--r--Source/WebKit/qt/tests/qwebview/.gitignore1
-rw-r--r--Source/WebKit/qt/tests/qwebview/qwebview.pro3
-rw-r--r--Source/WebKit/qt/tests/qwebview/resources/frame_a.html2
-rw-r--r--Source/WebKit/qt/tests/qwebview/resources/index.html4
-rw-r--r--Source/WebKit/qt/tests/qwebview/resources/input_types.html9
-rw-r--r--Source/WebKit/qt/tests/qwebview/tst_qwebview.cpp516
-rw-r--r--Source/WebKit/qt/tests/qwebview/tst_qwebview.qrc8
-rw-r--r--Source/WebKit/qt/tests/resources/image2.pngbin0 -> 14743 bytes
-rw-r--r--Source/WebKit/qt/tests/resources/test.swfbin0 -> 10085 bytes
-rw-r--r--Source/WebKit/qt/tests/tests.pri36
-rw-r--r--Source/WebKit/qt/tests/tests.pro8
-rw-r--r--Source/WebKit/qt/tests/util.h78
119 files changed, 13177 insertions, 0 deletions
diff --git a/Source/WebKit/qt/tests/MIMESniffing/MIMESniffing.pro b/Source/WebKit/qt/tests/MIMESniffing/MIMESniffing.pro
new file mode 100644
index 0000000..53d80c8
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/MIMESniffing.pro
@@ -0,0 +1,19 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+TARGET = MIMESniffing
+CONFIG += console
+
+SOURCES += ../../../../WebCore/platform/network/MIMESniffing.cpp
+HEADERS += \
+ ../../../../WebCore/platform/network/MIMESniffing.h \
+ TestData.h
+
+INCLUDEPATH += \
+ ../../../../WebCore/platform/network \
+ ../../../../JavaScriptCore
+
+debug {
+ SOURCES += ../../../../JavaScriptCore/wtf/Assertions.cpp
+}
+
+RESOURCES += resources.qrc
diff --git a/Source/WebKit/qt/tests/MIMESniffing/TestData.h b/Source/WebKit/qt/tests/MIMESniffing/TestData.h
new file mode 100644
index 0000000..c04bd6b
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/TestData.h
@@ -0,0 +1,984 @@
+/*
+ Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef TestData_h
+#define TestData_h
+
+typedef struct _TestData {
+ const char* file;
+ const char* advertisedType;
+ bool isImage;
+ const char* sniffedType;
+} TestData;
+
+static const TestData testList[] = {
+ {":/application_atom+xml", "text/plain", false, "text/plain"},
+ {":/application_atom+xml", "text/plain", true, "text/plain"},
+ {":/application_atom+xml", "unknown/unknown", false, "text/xml"},
+ {":/application_atom+xml", "unknown/unknown", true, "text/xml"},
+ {":/application_atom+xml", "application/unknown", false, "text/xml"},
+ {":/application_atom+xml", "application/unknown", true, "text/xml"},
+ {":/application_atom+xml", "*/*", false, "text/xml"},
+ {":/application_atom+xml", "*/*", true, "text/xml"},
+ {":/application_atom+xml", "text/xml", false, 0},
+ {":/application_atom+xml", "text/xml", true, 0},
+ {":/application_atom+xml", "application/xml", false, 0},
+ {":/application_atom+xml", "application/xml", true, 0},
+ {":/application_atom+xml", "text/html", false, "application/atom+xml"},
+ {":/application_atom+xml", "text/html", true, 0},
+ {":/application_atom+xml", "text/xml", false, 0},
+ {":/application_atom+xml", "text/xml", true, 0},
+ {":/application_atom+xml", "application/pdf", false, 0},
+ {":/application_atom+xml", "application/pdf", true, 0},
+ {":/application_atom+xml", "application/postscript", false, 0},
+ {":/application_atom+xml", "application/postscript", true, 0},
+ {":/application_atom+xml", "application/ogg", false, 0},
+ {":/application_atom+xml", "application/ogg", true, 0},
+ {":/application_atom+xml", "video/webm", false, 0},
+ {":/application_atom+xml", "video/webm", true, 0},
+ {":/application_atom+xml", "application/x-rar-compressed", false, 0},
+ {":/application_atom+xml", "application/x-rar-compressed", true, 0},
+ {":/application_atom+xml", "application/zip", false, 0},
+ {":/application_atom+xml", "application/zip", true, 0},
+ {":/application_atom+xml", "application/x-gzip", false, 0},
+ {":/application_atom+xml", "application/x-gzip", true, 0},
+ {":/application_atom+xml", "audio/x-wave", false, 0},
+ {":/application_atom+xml", "audio/x-wave", true, 0},
+ {":/application_atom+xml", "image/webp", false, 0},
+ {":/application_atom+xml", "image/webp", true, 0},
+ {":/application_atom+xml", "image/gif", false, 0},
+ {":/application_atom+xml", "image/gif", true, 0},
+ {":/application_atom+xml", "image/png", false, 0},
+ {":/application_atom+xml", "image/png", true, 0},
+ {":/application_atom+xml", "image/jpeg", false, 0},
+ {":/application_atom+xml", "image/jpeg", true, 0},
+ {":/application_atom+xml", "image/bmp", false, 0},
+ {":/application_atom+xml", "image/bmp", true, 0},
+ {":/application_atom+xml", "image/vnd.microsoft.icon", false, 0},
+ {":/application_atom+xml", "image/vnd.microsoft.icon", true, 0},
+ {":/application_atom+xml", "application/rdf+xml", false, 0},
+ {":/application_atom+xml", "application/rdf+xml", true, 0},
+ {":/application_atom+xml", "application/rss+xml", false, 0},
+ {":/application_atom+xml", "application/rss+xml", true, 0},
+ {":/application_atom+xml", "application/atom+xml", false, 0},
+ {":/application_atom+xml", "application/atom+xml", true, 0},
+ {":/application_ogg", "text/plain", false, "application/ogg"},
+ {":/application_ogg", "text/plain", true, "application/ogg"},
+ {":/application_ogg", "unknown/unknown", false, "application/ogg"},
+ {":/application_ogg", "unknown/unknown", true, "application/ogg"},
+ {":/application_ogg", "application/unknown", false, "application/ogg"},
+ {":/application_ogg", "application/unknown", true, "application/ogg"},
+ {":/application_ogg", "*/*", false, "application/ogg"},
+ {":/application_ogg", "*/*", true, "application/ogg"},
+ {":/application_ogg", "text/xml", false, 0},
+ {":/application_ogg", "text/xml", true, 0},
+ {":/application_ogg", "application/xml", false, 0},
+ {":/application_ogg", "application/xml", true, 0},
+ {":/application_ogg", "text/html", false, 0},
+ {":/application_ogg", "text/html", true, 0},
+ {":/application_ogg", "text/xml", false, 0},
+ {":/application_ogg", "text/xml", true, 0},
+ {":/application_ogg", "application/pdf", false, 0},
+ {":/application_ogg", "application/pdf", true, 0},
+ {":/application_ogg", "application/postscript", false, 0},
+ {":/application_ogg", "application/postscript", true, 0},
+ {":/application_ogg", "application/ogg", false, 0},
+ {":/application_ogg", "application/ogg", true, 0},
+ {":/application_ogg", "video/webm", false, 0},
+ {":/application_ogg", "video/webm", true, 0},
+ {":/application_ogg", "application/x-rar-compressed", false, 0},
+ {":/application_ogg", "application/x-rar-compressed", true, 0},
+ {":/application_ogg", "application/zip", false, 0},
+ {":/application_ogg", "application/zip", true, 0},
+ {":/application_ogg", "application/x-gzip", false, 0},
+ {":/application_ogg", "application/x-gzip", true, 0},
+ {":/application_ogg", "audio/x-wave", false, 0},
+ {":/application_ogg", "audio/x-wave", true, 0},
+ {":/application_ogg", "image/webp", false, 0},
+ {":/application_ogg", "image/webp", true, 0},
+ {":/application_ogg", "image/gif", false, 0},
+ {":/application_ogg", "image/gif", true, 0},
+ {":/application_ogg", "image/png", false, 0},
+ {":/application_ogg", "image/png", true, 0},
+ {":/application_ogg", "image/jpeg", false, 0},
+ {":/application_ogg", "image/jpeg", true, 0},
+ {":/application_ogg", "image/bmp", false, 0},
+ {":/application_ogg", "image/bmp", true, 0},
+ {":/application_ogg", "image/vnd.microsoft.icon", false, 0},
+ {":/application_ogg", "image/vnd.microsoft.icon", true, 0},
+ {":/application_ogg", "application/rdf+xml", false, 0},
+ {":/application_ogg", "application/rdf+xml", true, 0},
+ {":/application_ogg", "application/rss+xml", false, 0},
+ {":/application_ogg", "application/rss+xml", true, 0},
+ {":/application_ogg", "application/atom+xml", false, 0},
+ {":/application_ogg", "application/atom+xml", true, 0},
+ {":/application_pdf", "text/plain", false, "application/octet-stream"},
+ {":/application_pdf", "text/plain", true, "application/octet-stream"},
+ {":/application_pdf", "unknown/unknown", false, "application/pdf"},
+ {":/application_pdf", "unknown/unknown", true, "application/pdf"},
+ {":/application_pdf", "application/unknown", false, "application/pdf"},
+ {":/application_pdf", "application/unknown", true, "application/pdf"},
+ {":/application_pdf", "*/*", false, "application/pdf"},
+ {":/application_pdf", "*/*", true, "application/pdf"},
+ {":/application_pdf", "text/xml", false, 0},
+ {":/application_pdf", "text/xml", true, 0},
+ {":/application_pdf", "application/xml", false, 0},
+ {":/application_pdf", "application/xml", true, 0},
+ {":/application_pdf", "text/html", false, 0},
+ {":/application_pdf", "text/html", true, 0},
+ {":/application_pdf", "text/xml", false, 0},
+ {":/application_pdf", "text/xml", true, 0},
+ {":/application_pdf", "application/pdf", false, 0},
+ {":/application_pdf", "application/pdf", true, 0},
+ {":/application_pdf", "application/postscript", false, 0},
+ {":/application_pdf", "application/postscript", true, 0},
+ {":/application_pdf", "application/ogg", false, 0},
+ {":/application_pdf", "application/ogg", true, 0},
+ {":/application_pdf", "video/webm", false, 0},
+ {":/application_pdf", "video/webm", true, 0},
+ {":/application_pdf", "application/x-rar-compressed", false, 0},
+ {":/application_pdf", "application/x-rar-compressed", true, 0},
+ {":/application_pdf", "application/zip", false, 0},
+ {":/application_pdf", "application/zip", true, 0},
+ {":/application_pdf", "application/x-gzip", false, 0},
+ {":/application_pdf", "application/x-gzip", true, 0},
+ {":/application_pdf", "audio/x-wave", false, 0},
+ {":/application_pdf", "audio/x-wave", true, 0},
+ {":/application_pdf", "image/webp", false, 0},
+ {":/application_pdf", "image/webp", true, 0},
+ {":/application_pdf", "image/gif", false, 0},
+ {":/application_pdf", "image/gif", true, 0},
+ {":/application_pdf", "image/png", false, 0},
+ {":/application_pdf", "image/png", true, 0},
+ {":/application_pdf", "image/jpeg", false, 0},
+ {":/application_pdf", "image/jpeg", true, 0},
+ {":/application_pdf", "image/bmp", false, 0},
+ {":/application_pdf", "image/bmp", true, 0},
+ {":/application_pdf", "image/vnd.microsoft.icon", false, 0},
+ {":/application_pdf", "image/vnd.microsoft.icon", true, 0},
+ {":/application_pdf", "application/rdf+xml", false, 0},
+ {":/application_pdf", "application/rdf+xml", true, 0},
+ {":/application_pdf", "application/rss+xml", false, 0},
+ {":/application_pdf", "application/rss+xml", true, 0},
+ {":/application_pdf", "application/atom+xml", false, 0},
+ {":/application_pdf", "application/atom+xml", true, 0},
+ {":/application_postscript", "text/plain", false, "text/plain"},
+ {":/application_postscript", "text/plain", true, "text/plain"},
+ {":/application_postscript", "unknown/unknown", false, "application/postscript"},
+ {":/application_postscript", "unknown/unknown", true, "application/postscript"},
+ {":/application_postscript", "application/unknown", false, "application/postscript"},
+ {":/application_postscript", "application/unknown", true, "application/postscript"},
+ {":/application_postscript", "*/*", false, "application/postscript"},
+ {":/application_postscript", "*/*", true, "application/postscript"},
+ {":/application_postscript", "text/xml", false, 0},
+ {":/application_postscript", "text/xml", true, 0},
+ {":/application_postscript", "application/xml", false, 0},
+ {":/application_postscript", "application/xml", true, 0},
+ {":/application_postscript", "text/html", false, 0},
+ {":/application_postscript", "text/html", true, 0},
+ {":/application_postscript", "text/xml", false, 0},
+ {":/application_postscript", "text/xml", true, 0},
+ {":/application_postscript", "application/pdf", false, 0},
+ {":/application_postscript", "application/pdf", true, 0},
+ {":/application_postscript", "application/postscript", false, 0},
+ {":/application_postscript", "application/postscript", true, 0},
+ {":/application_postscript", "application/ogg", false, 0},
+ {":/application_postscript", "application/ogg", true, 0},
+ {":/application_postscript", "video/webm", false, 0},
+ {":/application_postscript", "video/webm", true, 0},
+ {":/application_postscript", "application/x-rar-compressed", false, 0},
+ {":/application_postscript", "application/x-rar-compressed", true, 0},
+ {":/application_postscript", "application/zip", false, 0},
+ {":/application_postscript", "application/zip", true, 0},
+ {":/application_postscript", "application/x-gzip", false, 0},
+ {":/application_postscript", "application/x-gzip", true, 0},
+ {":/application_postscript", "audio/x-wave", false, 0},
+ {":/application_postscript", "audio/x-wave", true, 0},
+ {":/application_postscript", "image/webp", false, 0},
+ {":/application_postscript", "image/webp", true, 0},
+ {":/application_postscript", "image/gif", false, 0},
+ {":/application_postscript", "image/gif", true, 0},
+ {":/application_postscript", "image/png", false, 0},
+ {":/application_postscript", "image/png", true, 0},
+ {":/application_postscript", "image/jpeg", false, 0},
+ {":/application_postscript", "image/jpeg", true, 0},
+ {":/application_postscript", "image/bmp", false, 0},
+ {":/application_postscript", "image/bmp", true, 0},
+ {":/application_postscript", "image/vnd.microsoft.icon", false, 0},
+ {":/application_postscript", "image/vnd.microsoft.icon", true, 0},
+ {":/application_postscript", "application/rdf+xml", false, 0},
+ {":/application_postscript", "application/rdf+xml", true, 0},
+ {":/application_postscript", "application/rss+xml", false, 0},
+ {":/application_postscript", "application/rss+xml", true, 0},
+ {":/application_postscript", "application/atom+xml", false, 0},
+ {":/application_postscript", "application/atom+xml", true, 0},
+ {":/application_rdf+xml", "text/plain", false, "text/plain"},
+ {":/application_rdf+xml", "text/plain", true, "text/plain"},
+ {":/application_rdf+xml", "unknown/unknown", false, "text/xml"},
+ {":/application_rdf+xml", "unknown/unknown", true, "text/xml"},
+ {":/application_rdf+xml", "application/unknown", false, "text/xml"},
+ {":/application_rdf+xml", "application/unknown", true, "text/xml"},
+ {":/application_rdf+xml", "*/*", false, "text/xml"},
+ {":/application_rdf+xml", "*/*", true, "text/xml"},
+ {":/application_rdf+xml", "text/xml", false, 0},
+ {":/application_rdf+xml", "text/xml", true, 0},
+ {":/application_rdf+xml", "application/xml", false, 0},
+ {":/application_rdf+xml", "application/xml", true, 0},
+ {":/application_rdf+xml", "text/html", false, "application/rdf+xml"},
+ {":/application_rdf+xml", "text/html", true, 0},
+ {":/application_rdf+xml", "text/xml", false, 0},
+ {":/application_rdf+xml", "text/xml", true, 0},
+ {":/application_rdf+xml", "application/pdf", false, 0},
+ {":/application_rdf+xml", "application/pdf", true, 0},
+ {":/application_rdf+xml", "application/postscript", false, 0},
+ {":/application_rdf+xml", "application/postscript", true, 0},
+ {":/application_rdf+xml", "application/ogg", false, 0},
+ {":/application_rdf+xml", "application/ogg", true, 0},
+ {":/application_rdf+xml", "video/webm", false, 0},
+ {":/application_rdf+xml", "video/webm", true, 0},
+ {":/application_rdf+xml", "application/x-rar-compressed", false, 0},
+ {":/application_rdf+xml", "application/x-rar-compressed", true, 0},
+ {":/application_rdf+xml", "application/zip", false, 0},
+ {":/application_rdf+xml", "application/zip", true, 0},
+ {":/application_rdf+xml", "application/x-gzip", false, 0},
+ {":/application_rdf+xml", "application/x-gzip", true, 0},
+ {":/application_rdf+xml", "audio/x-wave", false, 0},
+ {":/application_rdf+xml", "audio/x-wave", true, 0},
+ {":/application_rdf+xml", "image/webp", false, 0},
+ {":/application_rdf+xml", "image/webp", true, 0},
+ {":/application_rdf+xml", "image/gif", false, 0},
+ {":/application_rdf+xml", "image/gif", true, 0},
+ {":/application_rdf+xml", "image/png", false, 0},
+ {":/application_rdf+xml", "image/png", true, 0},
+ {":/application_rdf+xml", "image/jpeg", false, 0},
+ {":/application_rdf+xml", "image/jpeg", true, 0},
+ {":/application_rdf+xml", "image/bmp", false, 0},
+ {":/application_rdf+xml", "image/bmp", true, 0},
+ {":/application_rdf+xml", "image/vnd.microsoft.icon", false, 0},
+ {":/application_rdf+xml", "image/vnd.microsoft.icon", true, 0},
+ {":/application_rdf+xml", "application/rdf+xml", false, 0},
+ {":/application_rdf+xml", "application/rdf+xml", true, 0},
+ {":/application_rdf+xml", "application/rss+xml", false, 0},
+ {":/application_rdf+xml", "application/rss+xml", true, 0},
+ {":/application_rdf+xml", "application/atom+xml", false, 0},
+ {":/application_rdf+xml", "application/atom+xml", true, 0},
+ {":/application_rss+xml", "text/plain", false, "text/plain"},
+ {":/application_rss+xml", "text/plain", true, "text/plain"},
+ {":/application_rss+xml", "unknown/unknown", false, "text/xml"},
+ {":/application_rss+xml", "unknown/unknown", true, "text/xml"},
+ {":/application_rss+xml", "application/unknown", false, "text/xml"},
+ {":/application_rss+xml", "application/unknown", true, "text/xml"},
+ {":/application_rss+xml", "*/*", false, "text/xml"},
+ {":/application_rss+xml", "*/*", true, "text/xml"},
+ {":/application_rss+xml", "text/xml", false, 0},
+ {":/application_rss+xml", "text/xml", true, 0},
+ {":/application_rss+xml", "application/xml", false, 0},
+ {":/application_rss+xml", "application/xml", true, 0},
+ {":/application_rss+xml", "text/html", false, "application/rss+xml"},
+ {":/application_rss+xml", "text/html", true, 0},
+ {":/application_rss+xml", "text/xml", false, 0},
+ {":/application_rss+xml", "text/xml", true, 0},
+ {":/application_rss+xml", "application/pdf", false, 0},
+ {":/application_rss+xml", "application/pdf", true, 0},
+ {":/application_rss+xml", "application/postscript", false, 0},
+ {":/application_rss+xml", "application/postscript", true, 0},
+ {":/application_rss+xml", "application/ogg", false, 0},
+ {":/application_rss+xml", "application/ogg", true, 0},
+ {":/application_rss+xml", "video/webm", false, 0},
+ {":/application_rss+xml", "video/webm", true, 0},
+ {":/application_rss+xml", "application/x-rar-compressed", false, 0},
+ {":/application_rss+xml", "application/x-rar-compressed", true, 0},
+ {":/application_rss+xml", "application/zip", false, 0},
+ {":/application_rss+xml", "application/zip", true, 0},
+ {":/application_rss+xml", "application/x-gzip", false, 0},
+ {":/application_rss+xml", "application/x-gzip", true, 0},
+ {":/application_rss+xml", "audio/x-wave", false, 0},
+ {":/application_rss+xml", "audio/x-wave", true, 0},
+ {":/application_rss+xml", "image/webp", false, 0},
+ {":/application_rss+xml", "image/webp", true, 0},
+ {":/application_rss+xml", "image/gif", false, 0},
+ {":/application_rss+xml", "image/gif", true, 0},
+ {":/application_rss+xml", "image/png", false, 0},
+ {":/application_rss+xml", "image/png", true, 0},
+ {":/application_rss+xml", "image/jpeg", false, 0},
+ {":/application_rss+xml", "image/jpeg", true, 0},
+ {":/application_rss+xml", "image/bmp", false, 0},
+ {":/application_rss+xml", "image/bmp", true, 0},
+ {":/application_rss+xml", "image/vnd.microsoft.icon", false, 0},
+ {":/application_rss+xml", "image/vnd.microsoft.icon", true, 0},
+ {":/application_rss+xml", "application/rdf+xml", false, 0},
+ {":/application_rss+xml", "application/rdf+xml", true, 0},
+ {":/application_rss+xml", "application/rss+xml", false, 0},
+ {":/application_rss+xml", "application/rss+xml", true, 0},
+ {":/application_rss+xml", "application/atom+xml", false, 0},
+ {":/application_rss+xml", "application/atom+xml", true, 0},
+ {":/application_x-gzip", "text/plain", false, "application/x-gzip"},
+ {":/application_x-gzip", "text/plain", true, "application/x-gzip"},
+ {":/application_x-gzip", "unknown/unknown", false, "application/x-gzip"},
+ {":/application_x-gzip", "unknown/unknown", true, "application/x-gzip"},
+ {":/application_x-gzip", "application/unknown", false, "application/x-gzip"},
+ {":/application_x-gzip", "application/unknown", true, "application/x-gzip"},
+ {":/application_x-gzip", "*/*", false, "application/x-gzip"},
+ {":/application_x-gzip", "*/*", true, "application/x-gzip"},
+ {":/application_x-gzip", "text/xml", false, 0},
+ {":/application_x-gzip", "text/xml", true, 0},
+ {":/application_x-gzip", "application/xml", false, 0},
+ {":/application_x-gzip", "application/xml", true, 0},
+ {":/application_x-gzip", "text/html", false, 0},
+ {":/application_x-gzip", "text/html", true, 0},
+ {":/application_x-gzip", "text/xml", false, 0},
+ {":/application_x-gzip", "text/xml", true, 0},
+ {":/application_x-gzip", "application/pdf", false, 0},
+ {":/application_x-gzip", "application/pdf", true, 0},
+ {":/application_x-gzip", "application/postscript", false, 0},
+ {":/application_x-gzip", "application/postscript", true, 0},
+ {":/application_x-gzip", "application/ogg", false, 0},
+ {":/application_x-gzip", "application/ogg", true, 0},
+ {":/application_x-gzip", "video/webm", false, 0},
+ {":/application_x-gzip", "video/webm", true, 0},
+ {":/application_x-gzip", "application/x-rar-compressed", false, 0},
+ {":/application_x-gzip", "application/x-rar-compressed", true, 0},
+ {":/application_x-gzip", "application/zip", false, 0},
+ {":/application_x-gzip", "application/zip", true, 0},
+ {":/application_x-gzip", "application/x-gzip", false, 0},
+ {":/application_x-gzip", "application/x-gzip", true, 0},
+ {":/application_x-gzip", "audio/x-wave", false, 0},
+ {":/application_x-gzip", "audio/x-wave", true, 0},
+ {":/application_x-gzip", "image/webp", false, 0},
+ {":/application_x-gzip", "image/webp", true, 0},
+ {":/application_x-gzip", "image/gif", false, 0},
+ {":/application_x-gzip", "image/gif", true, 0},
+ {":/application_x-gzip", "image/png", false, 0},
+ {":/application_x-gzip", "image/png", true, 0},
+ {":/application_x-gzip", "image/jpeg", false, 0},
+ {":/application_x-gzip", "image/jpeg", true, 0},
+ {":/application_x-gzip", "image/bmp", false, 0},
+ {":/application_x-gzip", "image/bmp", true, 0},
+ {":/application_x-gzip", "image/vnd.microsoft.icon", false, 0},
+ {":/application_x-gzip", "image/vnd.microsoft.icon", true, 0},
+ {":/application_x-gzip", "application/rdf+xml", false, 0},
+ {":/application_x-gzip", "application/rdf+xml", true, 0},
+ {":/application_x-gzip", "application/rss+xml", false, 0},
+ {":/application_x-gzip", "application/rss+xml", true, 0},
+ {":/application_x-gzip", "application/atom+xml", false, 0},
+ {":/application_x-gzip", "application/atom+xml", true, 0},
+ {":/application_x-rar-compressed", "text/plain", false, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "text/plain", true, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "unknown/unknown", false, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "unknown/unknown", true, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "application/unknown", false, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "application/unknown", true, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "*/*", false, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "*/*", true, "application/x-rar-compressed"},
+ {":/application_x-rar-compressed", "text/xml", false, 0},
+ {":/application_x-rar-compressed", "text/xml", true, 0},
+ {":/application_x-rar-compressed", "application/xml", false, 0},
+ {":/application_x-rar-compressed", "application/xml", true, 0},
+ {":/application_x-rar-compressed", "text/html", false, 0},
+ {":/application_x-rar-compressed", "text/html", true, 0},
+ {":/application_x-rar-compressed", "text/xml", false, 0},
+ {":/application_x-rar-compressed", "text/xml", true, 0},
+ {":/application_x-rar-compressed", "application/pdf", false, 0},
+ {":/application_x-rar-compressed", "application/pdf", true, 0},
+ {":/application_x-rar-compressed", "application/postscript", false, 0},
+ {":/application_x-rar-compressed", "application/postscript", true, 0},
+ {":/application_x-rar-compressed", "application/ogg", false, 0},
+ {":/application_x-rar-compressed", "application/ogg", true, 0},
+ {":/application_x-rar-compressed", "video/webm", false, 0},
+ {":/application_x-rar-compressed", "video/webm", true, 0},
+ {":/application_x-rar-compressed", "application/x-rar-compressed", false, 0},
+ {":/application_x-rar-compressed", "application/x-rar-compressed", true, 0},
+ {":/application_x-rar-compressed", "application/zip", false, 0},
+ {":/application_x-rar-compressed", "application/zip", true, 0},
+ {":/application_x-rar-compressed", "application/x-gzip", false, 0},
+ {":/application_x-rar-compressed", "application/x-gzip", true, 0},
+ {":/application_x-rar-compressed", "audio/x-wave", false, 0},
+ {":/application_x-rar-compressed", "audio/x-wave", true, 0},
+ {":/application_x-rar-compressed", "image/webp", false, 0},
+ {":/application_x-rar-compressed", "image/webp", true, 0},
+ {":/application_x-rar-compressed", "image/gif", false, 0},
+ {":/application_x-rar-compressed", "image/gif", true, 0},
+ {":/application_x-rar-compressed", "image/png", false, 0},
+ {":/application_x-rar-compressed", "image/png", true, 0},
+ {":/application_x-rar-compressed", "image/jpeg", false, 0},
+ {":/application_x-rar-compressed", "image/jpeg", true, 0},
+ {":/application_x-rar-compressed", "image/bmp", false, 0},
+ {":/application_x-rar-compressed", "image/bmp", true, 0},
+ {":/application_x-rar-compressed", "image/vnd.microsoft.icon", false, 0},
+ {":/application_x-rar-compressed", "image/vnd.microsoft.icon", true, 0},
+ {":/application_x-rar-compressed", "application/rdf+xml", false, 0},
+ {":/application_x-rar-compressed", "application/rdf+xml", true, 0},
+ {":/application_x-rar-compressed", "application/rss+xml", false, 0},
+ {":/application_x-rar-compressed", "application/rss+xml", true, 0},
+ {":/application_x-rar-compressed", "application/atom+xml", false, 0},
+ {":/application_x-rar-compressed", "application/atom+xml", true, 0},
+ {":/application_zip", "text/plain", false, "application/zip"},
+ {":/application_zip", "text/plain", true, "application/zip"},
+ {":/application_zip", "unknown/unknown", false, "application/zip"},
+ {":/application_zip", "unknown/unknown", true, "application/zip"},
+ {":/application_zip", "application/unknown", false, "application/zip"},
+ {":/application_zip", "application/unknown", true, "application/zip"},
+ {":/application_zip", "*/*", false, "application/zip"},
+ {":/application_zip", "*/*", true, "application/zip"},
+ {":/application_zip", "text/xml", false, 0},
+ {":/application_zip", "text/xml", true, 0},
+ {":/application_zip", "application/xml", false, 0},
+ {":/application_zip", "application/xml", true, 0},
+ {":/application_zip", "text/html", false, 0},
+ {":/application_zip", "text/html", true, 0},
+ {":/application_zip", "text/xml", false, 0},
+ {":/application_zip", "text/xml", true, 0},
+ {":/application_zip", "application/pdf", false, 0},
+ {":/application_zip", "application/pdf", true, 0},
+ {":/application_zip", "application/postscript", false, 0},
+ {":/application_zip", "application/postscript", true, 0},
+ {":/application_zip", "application/ogg", false, 0},
+ {":/application_zip", "application/ogg", true, 0},
+ {":/application_zip", "video/webm", false, 0},
+ {":/application_zip", "video/webm", true, 0},
+ {":/application_zip", "application/x-rar-compressed", false, 0},
+ {":/application_zip", "application/x-rar-compressed", true, 0},
+ {":/application_zip", "application/zip", false, 0},
+ {":/application_zip", "application/zip", true, 0},
+ {":/application_zip", "application/x-gzip", false, 0},
+ {":/application_zip", "application/x-gzip", true, 0},
+ {":/application_zip", "audio/x-wave", false, 0},
+ {":/application_zip", "audio/x-wave", true, 0},
+ {":/application_zip", "image/webp", false, 0},
+ {":/application_zip", "image/webp", true, 0},
+ {":/application_zip", "image/gif", false, 0},
+ {":/application_zip", "image/gif", true, 0},
+ {":/application_zip", "image/png", false, 0},
+ {":/application_zip", "image/png", true, 0},
+ {":/application_zip", "image/jpeg", false, 0},
+ {":/application_zip", "image/jpeg", true, 0},
+ {":/application_zip", "image/bmp", false, 0},
+ {":/application_zip", "image/bmp", true, 0},
+ {":/application_zip", "image/vnd.microsoft.icon", false, 0},
+ {":/application_zip", "image/vnd.microsoft.icon", true, 0},
+ {":/application_zip", "application/rdf+xml", false, 0},
+ {":/application_zip", "application/rdf+xml", true, 0},
+ {":/application_zip", "application/rss+xml", false, 0},
+ {":/application_zip", "application/rss+xml", true, 0},
+ {":/application_zip", "application/atom+xml", false, 0},
+ {":/application_zip", "application/atom+xml", true, 0},
+ {":/audio_x-wave", "text/plain", false, "audio/x-wave"},
+ {":/audio_x-wave", "text/plain", true, "audio/x-wave"},
+ {":/audio_x-wave", "unknown/unknown", false, "audio/x-wave"},
+ {":/audio_x-wave", "unknown/unknown", true, "audio/x-wave"},
+ {":/audio_x-wave", "application/unknown", false, "audio/x-wave"},
+ {":/audio_x-wave", "application/unknown", true, "audio/x-wave"},
+ {":/audio_x-wave", "*/*", false, "audio/x-wave"},
+ {":/audio_x-wave", "*/*", true, "audio/x-wave"},
+ {":/audio_x-wave", "text/xml", false, 0},
+ {":/audio_x-wave", "text/xml", true, 0},
+ {":/audio_x-wave", "application/xml", false, 0},
+ {":/audio_x-wave", "application/xml", true, 0},
+ {":/audio_x-wave", "text/html", false, 0},
+ {":/audio_x-wave", "text/html", true, 0},
+ {":/audio_x-wave", "text/xml", false, 0},
+ {":/audio_x-wave", "text/xml", true, 0},
+ {":/audio_x-wave", "application/pdf", false, 0},
+ {":/audio_x-wave", "application/pdf", true, 0},
+ {":/audio_x-wave", "application/postscript", false, 0},
+ {":/audio_x-wave", "application/postscript", true, 0},
+ {":/audio_x-wave", "application/ogg", false, 0},
+ {":/audio_x-wave", "application/ogg", true, 0},
+ {":/audio_x-wave", "video/webm", false, 0},
+ {":/audio_x-wave", "video/webm", true, 0},
+ {":/audio_x-wave", "application/x-rar-compressed", false, 0},
+ {":/audio_x-wave", "application/x-rar-compressed", true, 0},
+ {":/audio_x-wave", "application/zip", false, 0},
+ {":/audio_x-wave", "application/zip", true, 0},
+ {":/audio_x-wave", "application/x-gzip", false, 0},
+ {":/audio_x-wave", "application/x-gzip", true, 0},
+ {":/audio_x-wave", "audio/x-wave", false, 0},
+ {":/audio_x-wave", "audio/x-wave", true, 0},
+ {":/audio_x-wave", "image/webp", false, 0},
+ {":/audio_x-wave", "image/webp", true, 0},
+ {":/audio_x-wave", "image/gif", false, 0},
+ {":/audio_x-wave", "image/gif", true, 0},
+ {":/audio_x-wave", "image/png", false, 0},
+ {":/audio_x-wave", "image/png", true, 0},
+ {":/audio_x-wave", "image/jpeg", false, 0},
+ {":/audio_x-wave", "image/jpeg", true, 0},
+ {":/audio_x-wave", "image/bmp", false, 0},
+ {":/audio_x-wave", "image/bmp", true, 0},
+ {":/audio_x-wave", "image/vnd.microsoft.icon", false, 0},
+ {":/audio_x-wave", "image/vnd.microsoft.icon", true, 0},
+ {":/audio_x-wave", "application/rdf+xml", false, 0},
+ {":/audio_x-wave", "application/rdf+xml", true, 0},
+ {":/audio_x-wave", "application/rss+xml", false, 0},
+ {":/audio_x-wave", "application/rss+xml", true, 0},
+ {":/audio_x-wave", "application/atom+xml", false, 0},
+ {":/audio_x-wave", "application/atom+xml", true, 0},
+ {":/image_bmp", "text/plain", false, "image/bmp"},
+ {":/image_bmp", "text/plain", true, "image/bmp"},
+ {":/image_bmp", "unknown/unknown", false, "image/bmp"},
+ {":/image_bmp", "unknown/unknown", true, "image/bmp"},
+ {":/image_bmp", "application/unknown", false, "image/bmp"},
+ {":/image_bmp", "application/unknown", true, "image/bmp"},
+ {":/image_bmp", "*/*", false, "image/bmp"},
+ {":/image_bmp", "*/*", true, "image/bmp"},
+ {":/image_bmp", "text/xml", false, 0},
+ {":/image_bmp", "text/xml", true, 0},
+ {":/image_bmp", "application/xml", false, 0},
+ {":/image_bmp", "application/xml", true, 0},
+ {":/image_bmp", "text/html", false, 0},
+ {":/image_bmp", "text/html", true, "image/bmp"},
+ {":/image_bmp", "text/xml", false, 0},
+ {":/image_bmp", "text/xml", true, 0},
+ {":/image_bmp", "application/pdf", false, 0},
+ {":/image_bmp", "application/pdf", true, "image/bmp"},
+ {":/image_bmp", "application/postscript", false, 0},
+ {":/image_bmp", "application/postscript", true, "image/bmp"},
+ {":/image_bmp", "application/ogg", false, 0},
+ {":/image_bmp", "application/ogg", true, "image/bmp"},
+ {":/image_bmp", "video/webm", false, 0},
+ {":/image_bmp", "video/webm", true, "image/bmp"},
+ {":/image_bmp", "application/x-rar-compressed", false, 0},
+ {":/image_bmp", "application/x-rar-compressed", true, "image/bmp"},
+ {":/image_bmp", "application/zip", false, 0},
+ {":/image_bmp", "application/zip", true, "image/bmp"},
+ {":/image_bmp", "application/x-gzip", false, 0},
+ {":/image_bmp", "application/x-gzip", true, "image/bmp"},
+ {":/image_bmp", "audio/x-wave", false, 0},
+ {":/image_bmp", "audio/x-wave", true, "image/bmp"},
+ {":/image_bmp", "image/webp", false, 0},
+ {":/image_bmp", "image/webp", true, "image/bmp"},
+ {":/image_bmp", "image/gif", false, 0},
+ {":/image_bmp", "image/gif", true, "image/bmp"},
+ {":/image_bmp", "image/png", false, 0},
+ {":/image_bmp", "image/png", true, "image/bmp"},
+ {":/image_bmp", "image/jpeg", false, 0},
+ {":/image_bmp", "image/jpeg", true, "image/bmp"},
+ {":/image_bmp", "image/bmp", false, 0},
+ {":/image_bmp", "image/bmp", true, "image/bmp"},
+ {":/image_bmp", "image/vnd.microsoft.icon", false, 0},
+ {":/image_bmp", "image/vnd.microsoft.icon", true, "image/bmp"},
+ {":/image_bmp", "application/rdf+xml", false, 0},
+ {":/image_bmp", "application/rdf+xml", true, 0},
+ {":/image_bmp", "application/rss+xml", false, 0},
+ {":/image_bmp", "application/rss+xml", true, 0},
+ {":/image_bmp", "application/atom+xml", false, 0},
+ {":/image_bmp", "application/atom+xml", true, 0},
+ {":/image_gif", "text/plain", false, "image/gif"},
+ {":/image_gif", "text/plain", true, "image/gif"},
+ {":/image_gif", "unknown/unknown", false, "image/gif"},
+ {":/image_gif", "unknown/unknown", true, "image/gif"},
+ {":/image_gif", "application/unknown", false, "image/gif"},
+ {":/image_gif", "application/unknown", true, "image/gif"},
+ {":/image_gif", "*/*", false, "image/gif"},
+ {":/image_gif", "*/*", true, "image/gif"},
+ {":/image_gif", "text/xml", false, 0},
+ {":/image_gif", "text/xml", true, 0},
+ {":/image_gif", "application/xml", false, 0},
+ {":/image_gif", "application/xml", true, 0},
+ {":/image_gif", "text/html", false, 0},
+ {":/image_gif", "text/html", true, "image/gif"},
+ {":/image_gif", "text/xml", false, 0},
+ {":/image_gif", "text/xml", true, 0},
+ {":/image_gif", "application/pdf", false, 0},
+ {":/image_gif", "application/pdf", true, "image/gif"},
+ {":/image_gif", "application/postscript", false, 0},
+ {":/image_gif", "application/postscript", true, "image/gif"},
+ {":/image_gif", "application/ogg", false, 0},
+ {":/image_gif", "application/ogg", true, "image/gif"},
+ {":/image_gif", "video/webm", false, 0},
+ {":/image_gif", "video/webm", true, "image/gif"},
+ {":/image_gif", "application/x-rar-compressed", false, 0},
+ {":/image_gif", "application/x-rar-compressed", true, "image/gif"},
+ {":/image_gif", "application/zip", false, 0},
+ {":/image_gif", "application/zip", true, "image/gif"},
+ {":/image_gif", "application/x-gzip", false, 0},
+ {":/image_gif", "application/x-gzip", true, "image/gif"},
+ {":/image_gif", "audio/x-wave", false, 0},
+ {":/image_gif", "audio/x-wave", true, "image/gif"},
+ {":/image_gif", "image/webp", false, 0},
+ {":/image_gif", "image/webp", true, "image/gif"},
+ {":/image_gif", "image/gif", false, 0},
+ {":/image_gif", "image/gif", true, "image/gif"},
+ {":/image_gif", "image/png", false, 0},
+ {":/image_gif", "image/png", true, "image/gif"},
+ {":/image_gif", "image/jpeg", false, 0},
+ {":/image_gif", "image/jpeg", true, "image/gif"},
+ {":/image_gif", "image/bmp", false, 0},
+ {":/image_gif", "image/bmp", true, "image/gif"},
+ {":/image_gif", "image/vnd.microsoft.icon", false, 0},
+ {":/image_gif", "image/vnd.microsoft.icon", true, "image/gif"},
+ {":/image_gif", "application/rdf+xml", false, 0},
+ {":/image_gif", "application/rdf+xml", true, 0},
+ {":/image_gif", "application/rss+xml", false, 0},
+ {":/image_gif", "application/rss+xml", true, 0},
+ {":/image_gif", "application/atom+xml", false, 0},
+ {":/image_gif", "application/atom+xml", true, 0},
+ {":/image_jpeg", "text/plain", false, "image/jpeg"},
+ {":/image_jpeg", "text/plain", true, "image/jpeg"},
+ {":/image_jpeg", "unknown/unknown", false, "image/jpeg"},
+ {":/image_jpeg", "unknown/unknown", true, "image/jpeg"},
+ {":/image_jpeg", "application/unknown", false, "image/jpeg"},
+ {":/image_jpeg", "application/unknown", true, "image/jpeg"},
+ {":/image_jpeg", "*/*", false, "image/jpeg"},
+ {":/image_jpeg", "*/*", true, "image/jpeg"},
+ {":/image_jpeg", "text/xml", false, 0},
+ {":/image_jpeg", "text/xml", true, 0},
+ {":/image_jpeg", "application/xml", false, 0},
+ {":/image_jpeg", "application/xml", true, 0},
+ {":/image_jpeg", "text/html", false, 0},
+ {":/image_jpeg", "text/html", true, "image/jpeg"},
+ {":/image_jpeg", "text/xml", false, 0},
+ {":/image_jpeg", "text/xml", true, 0},
+ {":/image_jpeg", "application/pdf", false, 0},
+ {":/image_jpeg", "application/pdf", true, "image/jpeg"},
+ {":/image_jpeg", "application/postscript", false, 0},
+ {":/image_jpeg", "application/postscript", true, "image/jpeg"},
+ {":/image_jpeg", "application/ogg", false, 0},
+ {":/image_jpeg", "application/ogg", true, "image/jpeg"},
+ {":/image_jpeg", "video/webm", false, 0},
+ {":/image_jpeg", "video/webm", true, "image/jpeg"},
+ {":/image_jpeg", "application/x-rar-compressed", false, 0},
+ {":/image_jpeg", "application/x-rar-compressed", true, "image/jpeg"},
+ {":/image_jpeg", "application/zip", false, 0},
+ {":/image_jpeg", "application/zip", true, "image/jpeg"},
+ {":/image_jpeg", "application/x-gzip", false, 0},
+ {":/image_jpeg", "application/x-gzip", true, "image/jpeg"},
+ {":/image_jpeg", "audio/x-wave", false, 0},
+ {":/image_jpeg", "audio/x-wave", true, "image/jpeg"},
+ {":/image_jpeg", "image/webp", false, 0},
+ {":/image_jpeg", "image/webp", true, "image/jpeg"},
+ {":/image_jpeg", "image/gif", false, 0},
+ {":/image_jpeg", "image/gif", true, "image/jpeg"},
+ {":/image_jpeg", "image/png", false, 0},
+ {":/image_jpeg", "image/png", true, "image/jpeg"},
+ {":/image_jpeg", "image/jpeg", false, 0},
+ {":/image_jpeg", "image/jpeg", true, "image/jpeg"},
+ {":/image_jpeg", "image/bmp", false, 0},
+ {":/image_jpeg", "image/bmp", true, "image/jpeg"},
+ {":/image_jpeg", "image/vnd.microsoft.icon", false, 0},
+ {":/image_jpeg", "image/vnd.microsoft.icon", true, "image/jpeg"},
+ {":/image_jpeg", "application/rdf+xml", false, 0},
+ {":/image_jpeg", "application/rdf+xml", true, 0},
+ {":/image_jpeg", "application/rss+xml", false, 0},
+ {":/image_jpeg", "application/rss+xml", true, 0},
+ {":/image_jpeg", "application/atom+xml", false, 0},
+ {":/image_jpeg", "application/atom+xml", true, 0},
+ {":/image_png", "text/plain", false, "image/png"},
+ {":/image_png", "text/plain", true, "image/png"},
+ {":/image_png", "unknown/unknown", false, "image/png"},
+ {":/image_png", "unknown/unknown", true, "image/png"},
+ {":/image_png", "application/unknown", false, "image/png"},
+ {":/image_png", "application/unknown", true, "image/png"},
+ {":/image_png", "*/*", false, "image/png"},
+ {":/image_png", "*/*", true, "image/png"},
+ {":/image_png", "text/xml", false, 0},
+ {":/image_png", "text/xml", true, 0},
+ {":/image_png", "application/xml", false, 0},
+ {":/image_png", "application/xml", true, 0},
+ {":/image_png", "text/html", false, 0},
+ {":/image_png", "text/html", true, "image/png"},
+ {":/image_png", "text/xml", false, 0},
+ {":/image_png", "text/xml", true, 0},
+ {":/image_png", "application/pdf", false, 0},
+ {":/image_png", "application/pdf", true, "image/png"},
+ {":/image_png", "application/postscript", false, 0},
+ {":/image_png", "application/postscript", true, "image/png"},
+ {":/image_png", "application/ogg", false, 0},
+ {":/image_png", "application/ogg", true, "image/png"},
+ {":/image_png", "video/webm", false, 0},
+ {":/image_png", "video/webm", true, "image/png"},
+ {":/image_png", "application/x-rar-compressed", false, 0},
+ {":/image_png", "application/x-rar-compressed", true, "image/png"},
+ {":/image_png", "application/zip", false, 0},
+ {":/image_png", "application/zip", true, "image/png"},
+ {":/image_png", "application/x-gzip", false, 0},
+ {":/image_png", "application/x-gzip", true, "image/png"},
+ {":/image_png", "audio/x-wave", false, 0},
+ {":/image_png", "audio/x-wave", true, "image/png"},
+ {":/image_png", "image/webp", false, 0},
+ {":/image_png", "image/webp", true, "image/png"},
+ {":/image_png", "image/gif", false, 0},
+ {":/image_png", "image/gif", true, "image/png"},
+ {":/image_png", "image/png", false, 0},
+ {":/image_png", "image/png", true, "image/png"},
+ {":/image_png", "image/jpeg", false, 0},
+ {":/image_png", "image/jpeg", true, "image/png"},
+ {":/image_png", "image/bmp", false, 0},
+ {":/image_png", "image/bmp", true, "image/png"},
+ {":/image_png", "image/vnd.microsoft.icon", false, 0},
+ {":/image_png", "image/vnd.microsoft.icon", true, "image/png"},
+ {":/image_png", "application/rdf+xml", false, 0},
+ {":/image_png", "application/rdf+xml", true, 0},
+ {":/image_png", "application/rss+xml", false, 0},
+ {":/image_png", "application/rss+xml", true, 0},
+ {":/image_png", "application/atom+xml", false, 0},
+ {":/image_png", "application/atom+xml", true, 0},
+ {":/image_vnd.microsoft.icon", "text/plain", false, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "text/plain", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "unknown/unknown", false, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "unknown/unknown", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/unknown", false, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/unknown", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "*/*", false, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "*/*", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "text/xml", false, 0},
+ {":/image_vnd.microsoft.icon", "text/xml", true, 0},
+ {":/image_vnd.microsoft.icon", "application/xml", false, 0},
+ {":/image_vnd.microsoft.icon", "application/xml", true, 0},
+ {":/image_vnd.microsoft.icon", "text/html", false, 0},
+ {":/image_vnd.microsoft.icon", "text/html", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "text/xml", false, 0},
+ {":/image_vnd.microsoft.icon", "text/xml", true, 0},
+ {":/image_vnd.microsoft.icon", "application/pdf", false, 0},
+ {":/image_vnd.microsoft.icon", "application/pdf", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/postscript", false, 0},
+ {":/image_vnd.microsoft.icon", "application/postscript", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/ogg", false, 0},
+ {":/image_vnd.microsoft.icon", "application/ogg", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "video/webm", false, 0},
+ {":/image_vnd.microsoft.icon", "video/webm", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/x-rar-compressed", false, 0},
+ {":/image_vnd.microsoft.icon", "application/x-rar-compressed", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/zip", false, 0},
+ {":/image_vnd.microsoft.icon", "application/zip", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/x-gzip", false, 0},
+ {":/image_vnd.microsoft.icon", "application/x-gzip", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "audio/x-wave", false, 0},
+ {":/image_vnd.microsoft.icon", "audio/x-wave", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "image/webp", false, 0},
+ {":/image_vnd.microsoft.icon", "image/webp", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "image/gif", false, 0},
+ {":/image_vnd.microsoft.icon", "image/gif", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "image/png", false, 0},
+ {":/image_vnd.microsoft.icon", "image/png", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "image/jpeg", false, 0},
+ {":/image_vnd.microsoft.icon", "image/jpeg", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "image/bmp", false, 0},
+ {":/image_vnd.microsoft.icon", "image/bmp", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "image/vnd.microsoft.icon", false, 0},
+ {":/image_vnd.microsoft.icon", "image/vnd.microsoft.icon", true, "image/vnd.microsoft.icon"},
+ {":/image_vnd.microsoft.icon", "application/rdf+xml", false, 0},
+ {":/image_vnd.microsoft.icon", "application/rdf+xml", true, 0},
+ {":/image_vnd.microsoft.icon", "application/rss+xml", false, 0},
+ {":/image_vnd.microsoft.icon", "application/rss+xml", true, 0},
+ {":/image_vnd.microsoft.icon", "application/atom+xml", false, 0},
+ {":/image_vnd.microsoft.icon", "application/atom+xml", true, 0},
+ {":/image_webp", "text/plain", false, "image/webp"},
+ {":/image_webp", "text/plain", true, "image/webp"},
+ {":/image_webp", "unknown/unknown", false, "image/webp"},
+ {":/image_webp", "unknown/unknown", true, "image/webp"},
+ {":/image_webp", "application/unknown", false, "image/webp"},
+ {":/image_webp", "application/unknown", true, "image/webp"},
+ {":/image_webp", "*/*", false, "image/webp"},
+ {":/image_webp", "*/*", true, "image/webp"},
+ {":/image_webp", "text/xml", false, 0},
+ {":/image_webp", "text/xml", true, 0},
+ {":/image_webp", "application/xml", false, 0},
+ {":/image_webp", "application/xml", true, 0},
+ {":/image_webp", "text/html", false, 0},
+ {":/image_webp", "text/html", true, "image/webp"},
+ {":/image_webp", "text/xml", false, 0},
+ {":/image_webp", "text/xml", true, 0},
+ {":/image_webp", "application/pdf", false, 0},
+ {":/image_webp", "application/pdf", true, "image/webp"},
+ {":/image_webp", "application/postscript", false, 0},
+ {":/image_webp", "application/postscript", true, "image/webp"},
+ {":/image_webp", "application/ogg", false, 0},
+ {":/image_webp", "application/ogg", true, "image/webp"},
+ {":/image_webp", "video/webm", false, 0},
+ {":/image_webp", "video/webm", true, "image/webp"},
+ {":/image_webp", "application/x-rar-compressed", false, 0},
+ {":/image_webp", "application/x-rar-compressed", true, "image/webp"},
+ {":/image_webp", "application/zip", false, 0},
+ {":/image_webp", "application/zip", true, "image/webp"},
+ {":/image_webp", "application/x-gzip", false, 0},
+ {":/image_webp", "application/x-gzip", true, "image/webp"},
+ {":/image_webp", "audio/x-wave", false, 0},
+ {":/image_webp", "audio/x-wave", true, "image/webp"},
+ {":/image_webp", "image/webp", false, 0},
+ {":/image_webp", "image/webp", true, "image/webp"},
+ {":/image_webp", "image/gif", false, 0},
+ {":/image_webp", "image/gif", true, "image/webp"},
+ {":/image_webp", "image/png", false, 0},
+ {":/image_webp", "image/png", true, "image/webp"},
+ {":/image_webp", "image/jpeg", false, 0},
+ {":/image_webp", "image/jpeg", true, "image/webp"},
+ {":/image_webp", "image/bmp", false, 0},
+ {":/image_webp", "image/bmp", true, "image/webp"},
+ {":/image_webp", "image/vnd.microsoft.icon", false, 0},
+ {":/image_webp", "image/vnd.microsoft.icon", true, "image/webp"},
+ {":/image_webp", "application/rdf+xml", false, 0},
+ {":/image_webp", "application/rdf+xml", true, 0},
+ {":/image_webp", "application/rss+xml", false, 0},
+ {":/image_webp", "application/rss+xml", true, 0},
+ {":/image_webp", "application/atom+xml", false, 0},
+ {":/image_webp", "application/atom+xml", true, 0},
+ {":/text_html", "text/plain", false, "text/plain"},
+ {":/text_html", "text/plain", true, "text/plain"},
+ {":/text_html", "unknown/unknown", false, "text/html"},
+ {":/text_html", "unknown/unknown", true, "text/html"},
+ {":/text_html", "application/unknown", false, "text/html"},
+ {":/text_html", "application/unknown", true, "text/html"},
+ {":/text_html", "*/*", false, "text/html"},
+ {":/text_html", "*/*", true, "text/html"},
+ {":/text_html", "text/xml", false, 0},
+ {":/text_html", "text/xml", true, 0},
+ {":/text_html", "application/xml", false, 0},
+ {":/text_html", "application/xml", true, 0},
+ {":/text_html", "text/html", false, 0},
+ {":/text_html", "text/html", true, 0},
+ {":/text_html", "text/xml", false, 0},
+ {":/text_html", "text/xml", true, 0},
+ {":/text_html", "application/pdf", false, 0},
+ {":/text_html", "application/pdf", true, 0},
+ {":/text_html", "application/postscript", false, 0},
+ {":/text_html", "application/postscript", true, 0},
+ {":/text_html", "application/ogg", false, 0},
+ {":/text_html", "application/ogg", true, 0},
+ {":/text_html", "video/webm", false, 0},
+ {":/text_html", "video/webm", true, 0},
+ {":/text_html", "application/x-rar-compressed", false, 0},
+ {":/text_html", "application/x-rar-compressed", true, 0},
+ {":/text_html", "application/zip", false, 0},
+ {":/text_html", "application/zip", true, 0},
+ {":/text_html", "application/x-gzip", false, 0},
+ {":/text_html", "application/x-gzip", true, 0},
+ {":/text_html", "audio/x-wave", false, 0},
+ {":/text_html", "audio/x-wave", true, 0},
+ {":/text_html", "image/webp", false, 0},
+ {":/text_html", "image/webp", true, 0},
+ {":/text_html", "image/gif", false, 0},
+ {":/text_html", "image/gif", true, 0},
+ {":/text_html", "image/png", false, 0},
+ {":/text_html", "image/png", true, 0},
+ {":/text_html", "image/jpeg", false, 0},
+ {":/text_html", "image/jpeg", true, 0},
+ {":/text_html", "image/bmp", false, 0},
+ {":/text_html", "image/bmp", true, 0},
+ {":/text_html", "image/vnd.microsoft.icon", false, 0},
+ {":/text_html", "image/vnd.microsoft.icon", true, 0},
+ {":/text_html", "application/rdf+xml", false, 0},
+ {":/text_html", "application/rdf+xml", true, 0},
+ {":/text_html", "application/rss+xml", false, 0},
+ {":/text_html", "application/rss+xml", true, 0},
+ {":/text_html", "application/atom+xml", false, 0},
+ {":/text_html", "application/atom+xml", true, 0},
+ {":/text_xml", "text/plain", false, "text/plain"},
+ {":/text_xml", "text/plain", true, "text/plain"},
+ {":/text_xml", "unknown/unknown", false, "text/xml"},
+ {":/text_xml", "unknown/unknown", true, "text/xml"},
+ {":/text_xml", "application/unknown", false, "text/xml"},
+ {":/text_xml", "application/unknown", true, "text/xml"},
+ {":/text_xml", "*/*", false, "text/xml"},
+ {":/text_xml", "*/*", true, "text/xml"},
+ {":/text_xml", "text/xml", false, 0},
+ {":/text_xml", "text/xml", true, 0},
+ {":/text_xml", "application/xml", false, 0},
+ {":/text_xml", "application/xml", true, 0},
+ {":/text_xml", "text/html", false, 0},
+ {":/text_xml", "text/html", true, 0},
+ {":/text_xml", "text/xml", false, 0},
+ {":/text_xml", "text/xml", true, 0},
+ {":/text_xml", "application/pdf", false, 0},
+ {":/text_xml", "application/pdf", true, 0},
+ {":/text_xml", "application/postscript", false, 0},
+ {":/text_xml", "application/postscript", true, 0},
+ {":/text_xml", "application/ogg", false, 0},
+ {":/text_xml", "application/ogg", true, 0},
+ {":/text_xml", "video/webm", false, 0},
+ {":/text_xml", "video/webm", true, 0},
+ {":/text_xml", "application/x-rar-compressed", false, 0},
+ {":/text_xml", "application/x-rar-compressed", true, 0},
+ {":/text_xml", "application/zip", false, 0},
+ {":/text_xml", "application/zip", true, 0},
+ {":/text_xml", "application/x-gzip", false, 0},
+ {":/text_xml", "application/x-gzip", true, 0},
+ {":/text_xml", "audio/x-wave", false, 0},
+ {":/text_xml", "audio/x-wave", true, 0},
+ {":/text_xml", "image/webp", false, 0},
+ {":/text_xml", "image/webp", true, 0},
+ {":/text_xml", "image/gif", false, 0},
+ {":/text_xml", "image/gif", true, 0},
+ {":/text_xml", "image/png", false, 0},
+ {":/text_xml", "image/png", true, 0},
+ {":/text_xml", "image/jpeg", false, 0},
+ {":/text_xml", "image/jpeg", true, 0},
+ {":/text_xml", "image/bmp", false, 0},
+ {":/text_xml", "image/bmp", true, 0},
+ {":/text_xml", "image/vnd.microsoft.icon", false, 0},
+ {":/text_xml", "image/vnd.microsoft.icon", true, 0},
+ {":/text_xml", "application/rdf+xml", false, 0},
+ {":/text_xml", "application/rdf+xml", true, 0},
+ {":/text_xml", "application/rss+xml", false, 0},
+ {":/text_xml", "application/rss+xml", true, 0},
+ {":/text_xml", "application/atom+xml", false, 0},
+ {":/text_xml", "application/atom+xml", true, 0},
+ {":/video_webm", "text/plain", false, "video/webm"},
+ {":/video_webm", "text/plain", true, "video/webm"},
+ {":/video_webm", "unknown/unknown", false, "video/webm"},
+ {":/video_webm", "unknown/unknown", true, "video/webm"},
+ {":/video_webm", "application/unknown", false, "video/webm"},
+ {":/video_webm", "application/unknown", true, "video/webm"},
+ {":/video_webm", "*/*", false, "video/webm"},
+ {":/video_webm", "*/*", true, "video/webm"},
+ {":/video_webm", "text/xml", false, 0},
+ {":/video_webm", "text/xml", true, 0},
+ {":/video_webm", "application/xml", false, 0},
+ {":/video_webm", "application/xml", true, 0},
+ {":/video_webm", "text/html", false, 0},
+ {":/video_webm", "text/html", true, 0},
+ {":/video_webm", "text/xml", false, 0},
+ {":/video_webm", "text/xml", true, 0},
+ {":/video_webm", "application/pdf", false, 0},
+ {":/video_webm", "application/pdf", true, 0},
+ {":/video_webm", "application/postscript", false, 0},
+ {":/video_webm", "application/postscript", true, 0},
+ {":/video_webm", "application/ogg", false, 0},
+ {":/video_webm", "application/ogg", true, 0},
+ {":/video_webm", "video/webm", false, 0},
+ {":/video_webm", "video/webm", true, 0},
+ {":/video_webm", "application/x-rar-compressed", false, 0},
+ {":/video_webm", "application/x-rar-compressed", true, 0},
+ {":/video_webm", "application/zip", false, 0},
+ {":/video_webm", "application/zip", true, 0},
+ {":/video_webm", "application/x-gzip", false, 0},
+ {":/video_webm", "application/x-gzip", true, 0},
+ {":/video_webm", "audio/x-wave", false, 0},
+ {":/video_webm", "audio/x-wave", true, 0},
+ {":/video_webm", "image/webp", false, 0},
+ {":/video_webm", "image/webp", true, 0},
+ {":/video_webm", "image/gif", false, 0},
+ {":/video_webm", "image/gif", true, 0},
+ {":/video_webm", "image/png", false, 0},
+ {":/video_webm", "image/png", true, 0},
+ {":/video_webm", "image/jpeg", false, 0},
+ {":/video_webm", "image/jpeg", true, 0},
+ {":/video_webm", "image/bmp", false, 0},
+ {":/video_webm", "image/bmp", true, 0},
+ {":/video_webm", "image/vnd.microsoft.icon", false, 0},
+ {":/video_webm", "image/vnd.microsoft.icon", true, 0},
+ {":/video_webm", "application/rdf+xml", false, 0},
+ {":/video_webm", "application/rdf+xml", true, 0},
+ {":/video_webm", "application/rss+xml", false, 0},
+ {":/video_webm", "application/rss+xml", true, 0},
+ {":/video_webm", "application/atom+xml", false, 0},
+ {":/video_webm", "application/atom+xml", true, 0}
+};
+static const size_t testListSize = sizeof(testList) / sizeof(testList[0]);
+
+#endif // TestData_h
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources.qrc b/Source/WebKit/qt/tests/MIMESniffing/resources.qrc
new file mode 100644
index 0000000..b4afb32
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources.qrc
@@ -0,0 +1,23 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="application_atom+xml">resources/application_atom+xml</file>
+ <file alias="application_ogg">resources/application_ogg</file>
+ <file alias="application_pdf">resources/application_pdf</file>
+ <file alias="application_postscript">resources/application_postscript</file>
+ <file alias="application_rdf+xml">resources/application_rdf+xml</file>
+ <file alias="application_rss+xml">resources/application_rss+xml</file>
+ <file alias="application_x-gzip">resources/application_x-gzip</file>
+ <file alias="application_x-rar-compressed">resources/application_x-rar-compressed</file>
+ <file alias="application_zip">resources/application_zip</file>
+ <file alias="audio_x-wave">resources/audio_x-wave</file>
+ <file alias="image_bmp">resources/image_bmp</file>
+ <file alias="image_gif">resources/image_gif</file>
+ <file alias="image_jpeg">resources/image_jpeg</file>
+ <file alias="image_png">resources/image_png</file>
+ <file alias="image_vnd.microsoft.icon">resources/image_vnd.microsoft.icon</file>
+ <file alias="image_webp">resources/image_webp</file>
+ <file alias="text_html">resources/text_html</file>
+ <file alias="text_xml">resources/text_xml</file>
+ <file alias="video_webm">resources/video_webm</file>
+ </qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_atom+xml b/Source/WebKit/qt/tests/MIMESniffing/resources/application_atom+xml
new file mode 100644
index 0000000..54086a7
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_atom+xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <title>Example Feed</title>
+ <link href="http://example.org/"/>
+ <updated>2003-12-13T18:30:02Z</updated>
+ <author>
+ <name>John Doe</name>
+ </author>
+ <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+ <entry>
+ <title>Atom-Powered Robots Run Amok</title>
+ <link href="http://example.org/2003/12/13/atom03"/>
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+ <updated>2003-12-13T18:30:02Z</updated>
+ <summary>Some text.</summary>
+ </entry>
+</feed>
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_ogg b/Source/WebKit/qt/tests/MIMESniffing/resources/application_ogg
new file mode 100644
index 0000000..b9cc1b2
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_ogg
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_pdf b/Source/WebKit/qt/tests/MIMESniffing/resources/application_pdf
new file mode 100644
index 0000000..7f8996f
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_pdf
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_postscript b/Source/WebKit/qt/tests/MIMESniffing/resources/application_postscript
new file mode 100644
index 0000000..c4b9ae6
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_postscript
@@ -0,0 +1,137 @@
+%!PS-Adobe-2.0 EPSF-1.2
+%%Creator: HiJaak 2.1
+%%CreationDate: 12/29/93 13:52:08
+%%BoundingBox:126 216 486 576
+%%EndComments
+/ld {load def} bind def
+/s /stroke ld /f /fill ld /m /moveto ld /l /lineto ld /c /curveto ld /rgb {255 div 3 1 roll 255 div 3 1 roll 255 div 3 1 roll setrgbcolor} def
+126 216 translate
+360.0000 360.0000 scale
+/picstr 124 string def
+124 124 8 [124 0 0 -124 0 124] {currentfile picstr readhexstring pop} image
+65656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565ADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADAD1B1B1B1B1B1B1B1B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565006565656565006565656500656565656565000000656565656565656565656565656565656565656565656565656565656565ADADAD00ADADAD000000ADAD00ADADADADAD00AD00ADADADAD00ADADADAD00000000001B1B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565000065656500006565650065006565656500656565006565656565656565656565656565656565656565656565656565656565ADADAD00ADAD00ADADAD00ADAD00ADADAD00ADAD0000ADADAD00ADADADAD001B1B1B1B001B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565000065656500006565650065006565650065656565650065656565656565656565656565656565656565656565656565656565ADADAD00AD00ADADADADADADAD00ADADAD00ADAD00AD00ADAD00ADADADAD001B1B1B1B001B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565006500650065006565650065006565650065656565656565656565656565656565656565656565656565656565656565656565ADADAD00AD00ADADADADADADADAD00AD00ADADAD00AD00ADAD00ADADADAD00000000001B1B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565006500650065006565006565650065650065656500000065656565656565656565656565656565656565656565656565656565ADADAD00AD00ADADADADADADADADAD00ADADADAD00ADAD00AD00ADADADAD001B1B1B1B001B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565006500650065006565000000000065650065656565650065656565656565656565656565656565656565656565656565656565ADADAD00AD00ADADADADADADADADAD00ADADADAD00ADAD00AD00ADADADAD001B1B1B1B001B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565006565006565006500656565656500656500656565006565656565656565656565656565656565656565656565656565656565ADADAD00ADAD00ADADAD00ADADADAD00ADADADAD00ADADAD0000ADADADAD001B1B1B1B001B001B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565006565006565006500656565656500656565000000656565656565656565656565656565656565656565656565656565656565ADADAD00ADADAD000000ADADADADAD00ADADADAD00ADADADAD00ADADADAD00000000001B1B00000000FF
+65656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565ADADAD00ADADADADADADADADADADADADADADADADADADADADADADADADADADAD1B1B1B1B1B1B1B1B1B1BFF
+65656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565ADADAD00ADADADADADADADADADADADADADADADADADADADADADADADADADADAD1B1B1B1B1B1B1B1B1B1BFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC0000DCDC0000DC0000000000DC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292000000009292000000000092920000929200009292929292ADADADAD00000000ADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC0000DCDC0000DC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929200009292000092000092920000920000929200009292929292ADADAD0000ADAD0000ADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC00DCDC00DCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292920000929292929292000092920000920000009200009292929292ADAD0000ADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC00000000DCDC0000000000DC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292920000929292929292000092920000920000009200009292929292ADAD0000ADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC0000DCDCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292920000929200000092000000000092920000920000009292929292ADAD0000ADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC0000DCDCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292920000929292000092000092000092920000920000009292929292ADAD0000ADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC0000DCDCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929200009292000092000092920000920000929200009292929292ADADAD0000ADAD0000ADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC0000DCDCDC0000000000DC000000000000DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292000000009292000092929200000000929200009292929292ADADADAD00000000ADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+DCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC92929292929292929292929292929292929292929292929292929292929292ADADADADADADADADADADFF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00000000004A4A00000000004A00000000004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDC0000DCDC0000DC0000000000DC0000DCDCDCDCDCDCDCDCDCDCDC00000065656500000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00004A4A00004A00004A4A4A4A00004A4A00004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDC0000DCDC0000DC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDC00000065656500000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00004A4A00004A00004A4A4A4A00004A4A00004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDC00DCDC00DCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDC00000000650000000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00004A4A00004A00000000004A00004A4A00004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDC00000000DCDC0000000000DC0000DCDCDCDCDCDCDCDCDCDCDC00000000650000000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00000000004A4A00004A4A4A4A00004A4A00004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDC0000DCDCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDC00006500650065000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00004A00004A4A00004A4A4A4A00004A4A00004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDC0000DCDCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDC00006500000065000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00004A4A00004A00004A4A4A4A00004A4A00004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDC0000DCDCDC0000DCDCDCDC0000DCDCDCDCDCDCDCDCDCDCDC00006500000065000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A00004A4A4A000000000000004A00000000004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDC0000DCDCDC0000000000DC000000000000DCDCDCDCDCDCDC00006565006565000065FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A00000000004A4A4A4A0000004A4A4A00000000004A4A4A4A004A4A4A4A4A00000000004A00000000004A00000000004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A004A4A4A4A004A4A004A4A4A004A4A4A4A004A4A4A4A4A4A004A4A4A4A4A004A4A4A4A4A004A4A4A4A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A004A4A4A4A004A004A4A4A4A4A004A4A4A004A4A4A4A4A4A004A4A4A4A4A004A4A4A4A4A004A4A4A4A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A00000000004A4A004A4A4A4A4A004A4A4A004A4A4A4A4A4A004A4A4A4A4A00000000004A000000004A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A004A4A4A4A004A004A4A4A4A4A004A4A4A004A4A4A4A4A4A004A4A4A4A4A004A4A4A4A4A004A4A4A4A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A004A4A4A4A004A004A4A4A4A4A004A4A4A004A4A4A4A4A4A004A4A4A4A4A004A4A4A4A4A004A4A4A4A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A004A4A4A4A004A4A004A4A4A004A4A4A4A004A4A4A4A4A4A004A4A4A4A4A004A4A4A4A4A004A4A4A4A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A00000000004A4A4A4A0000004A4A4A4A4A004A4A4A4A4A4A00000000004A00000000004A004A4A4A4A4A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4ADCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDC65656565656565656565FF
+showpage
+ \ No newline at end of file
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_rdf+xml b/Source/WebKit/qt/tests/MIMESniffing/resources/application_rdf+xml
new file mode 100644
index 0000000..e214145
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_rdf+xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/">
+
+ <channel rdf:about="http://www.xml.com/xml/news.rss">
+ <title>XML.com</title>
+ <link>http://xml.com/pub</link>
+ <description>
+ XML.com features a rich mix of information and services
+ for the XML community.
+ </description>
+
+ <image rdf:resource="http://xml.com/universal/images/xml_tiny.gif" />
+
+ <items>
+ <rdf:Seq>
+ <rdf:li resource="http://xml.com/pub/2000/08/09/xslt/xslt.html" />
+ <rdf:li resource="http://xml.com/pub/2000/08/09/rdfdb/index.html" />
+ </rdf:Seq>
+ </items>
+
+ </channel>
+
+ <image rdf:about="http://xml.com/universal/images/xml_tiny.gif">
+ <title>XML.com</title>
+ <link>http://www.xml.com</link>
+ <url>http://xml.com/universal/images/xml_tiny.gif</url>
+ </image>
+
+ <item rdf:about="http://xml.com/pub/2000/08/09/xslt/xslt.html">
+ <title>Processing Inclusions with XSLT</title>
+ <link>http://xml.com/pub/2000/08/09/xslt/xslt.html</link>
+ <description>
+ Processing document inclusions with general XML tools can be
+ problematic. This article proposes a way of preserving inclusion
+ information through SAX-based processing.
+ </description>
+ </item>
+
+ <item rdf:about="http://xml.com/pub/2000/08/09/rdfdb/index.html">
+ <title>Putting RDF to Work</title>
+ <link>http://xml.com/pub/2000/08/09/rdfdb/index.html</link>
+ <description>
+ Tool and API support for the Resource Description Framework
+ is slowly coming of age. Edd Dumbill takes a look at RDFDB,
+ one of the most exciting new RDF toolkits.
+ </description>
+ </item>
+
+</rdf:RDF>
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_rss+xml b/Source/WebKit/qt/tests/MIMESniffing/resources/application_rss+xml
new file mode 100644
index 0000000..3537c41
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_rss+xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<rss version="0.91">
+<channel>
+
+<title>Folha.com - Ambiente - Principal</title>
+<link>http://redir.folha.com.br/redir/online/ambiente/rss091/*http://www1.folha.uol.com.br/ambiente/</link>
+<description>Primeiro jornal em tempo real em língua portuguesa</description>
+<language>pt-br</language>
+<copyright>Copyright Folha.com. Todos os direitos reservados.</copyright>
+<docs>http://redir.folha.com.br/redir/online/ambiente/rss091/*http://www1.folha.uol.com.br/folha/conheca/arquivo_e_copyright.shtml</docs>
+<webMaster>webmaster@grupofolha.com.br (Webmaster Folha.com)</webMaster>
+
+<image>
+<title>Folha.com - Ambiente - Principal</title>
+<url>http://www1.folha.uol.com.br/folha/images/lgo-folha_com-88x31.gif</url>
+<link>http://redir.folha.com.br/redir/online/ambiente/rss091/*http://www1.folha.uol.com.br/ambiente/</link>
+<width>88</width>
+<height>31</height>
+<description>Primeiro jornal em tempo real em língua portuguesa</description>
+</image>
+
+<item>
+<title>Nasa dimensiona danos da seca na Amazônia em 2,4 mi de km2</title>
+<link>http://redir.folha.com.br/redir/online/ambiente/rss091/*http://www1.folha.uol.com.br/ambiente/895526-nasa-dimensiona-danos-da-seca-na-amazonia-em-24-mi-de-km2.shtml</link>
+<description>
+Os satélites da Nasa (agência espacial americana) forneceram material para uma análise dos estragos provocados pela &lt;a href=&quot;http://www1.folha.uol.com.br/ambiente/870588-amazonia-teve-a-pior-seca-dos-ultimos-cem-anos.shtml&quot;&gt;pior seca a atingir a Amazônia em 2010&lt;/a&gt;.
+Pela tomada aérea, estima-se que foram 2,5 milhões de quilômetros quadrados afetados --pouco menos da metade do ecossistema amazônico.
+&lt;table class=&quot;articleGraphic&quot;&gt;
+&lt;tr&gt;
+&lt;td rowspan=&quot;3&quot; class=&quot;articleGraphicSpace&quot;&gt;&lt;/td&gt;
+&lt;td class=&quot;articleGraphicCredit&quot;&gt;Universidade de Boston/Nasa&lt;/td&gt;
+&lt;td rowspan=&quot;3&quot; class=&quot;articleGraphicSpace&quot;&gt;&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+&lt;td class=&quot;articleGraphicImage&quot;&gt;&lt;img src=&quot;http://f.i.uol.com.br/folha/ambiente/images/11090120.jpeg&quot; alt=&quot;Área (vermelho) mostra redução do índice do verdor, onde a vegetação ficou menos verde e mais seca&quot; border=&quot;0&quot; /&gt;&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+&lt;td class=&quot;articleGraphicCaption&quot;&gt;Área (vermelho) mostra redução do índice do verdor, onde a vegetação ficou menos verde e mais seca&lt;/td&gt;
+&lt;/tr&gt;
+&lt;/table&gt;
+&lt;a href=&quot;http://redir.folha.com.br/redir/online/ambiente/rss091/*http://www1.folha.uol.com.br/ambiente/895526-nasa-dimensiona-danos-da-seca-na-amazonia-em-24-mi-de-km2.shtml&quot;&gt;Leia mais&lt;/a&gt; (29/03/2011 - 18h04)</description>
+<pubDate>29 Mar 2011 18:04:00 -0300</pubDate>
+</item>
+</channel>
+</rss>
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_x-gzip b/Source/WebKit/qt/tests/MIMESniffing/resources/application_x-gzip
new file mode 100644
index 0000000..a5e7d31
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_x-gzip
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_x-rar-compressed b/Source/WebKit/qt/tests/MIMESniffing/resources/application_x-rar-compressed
new file mode 100644
index 0000000..d9cb6ae
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_x-rar-compressed
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/application_zip b/Source/WebKit/qt/tests/MIMESniffing/resources/application_zip
new file mode 100644
index 0000000..8aec52f
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/application_zip
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/audio_x-wave b/Source/WebKit/qt/tests/MIMESniffing/resources/audio_x-wave
new file mode 100644
index 0000000..a0f9b85
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/audio_x-wave
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/image_bmp b/Source/WebKit/qt/tests/MIMESniffing/resources/image_bmp
new file mode 100644
index 0000000..b61d368
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/image_bmp
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/image_gif b/Source/WebKit/qt/tests/MIMESniffing/resources/image_gif
new file mode 100644
index 0000000..32b1ea2
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/image_gif
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/image_jpeg b/Source/WebKit/qt/tests/MIMESniffing/resources/image_jpeg
new file mode 100644
index 0000000..1874576
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/image_jpeg
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/image_png b/Source/WebKit/qt/tests/MIMESniffing/resources/image_png
new file mode 100644
index 0000000..bef59c7
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/image_png
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/image_vnd.microsoft.icon b/Source/WebKit/qt/tests/MIMESniffing/resources/image_vnd.microsoft.icon
new file mode 100644
index 0000000..58921b8
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/image_vnd.microsoft.icon
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/image_webp b/Source/WebKit/qt/tests/MIMESniffing/resources/image_webp
new file mode 100644
index 0000000..0da983e
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/image_webp
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/text_html b/Source/WebKit/qt/tests/MIMESniffing/resources/text_html
new file mode 100644
index 0000000..21eeee3
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/text_html
@@ -0,0 +1,3 @@
+
+<!-- saved from url=(0017)http://127.0.0.1/ -->
+<HTML><HEAD><META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"></HEAD><BODY><H1>It works!</H1></BODY></HTML> \ No newline at end of file
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/text_xml b/Source/WebKit/qt/tests/MIMESniffing/resources/text_xml
new file mode 100644
index 0000000..38a9fe5
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/text_xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<CATALOG>
+ <CD>
+ <TITLE>Empire Burlesque</TITLE>
+ <ARTIST>Bob Dylan</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>Columbia</COMPANY>
+ <PRICE>10.90</PRICE>
+ <YEAR>1985</YEAR>
+ </CD>
+ <CD>
+ <TITLE>Unchain my heart</TITLE>
+ <ARTIST>Joe Cocker</ARTIST>
+ <COUNTRY>USA</COUNTRY>
+ <COMPANY>EMI</COMPANY>
+ <PRICE>8.20</PRICE>
+ <YEAR>1987</YEAR>
+ </CD>
+</CATALOG>
diff --git a/Source/WebKit/qt/tests/MIMESniffing/resources/video_webm b/Source/WebKit/qt/tests/MIMESniffing/resources/video_webm
new file mode 100644
index 0000000..95d5031
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/resources/video_webm
Binary files differ
diff --git a/Source/WebKit/qt/tests/MIMESniffing/tst_MIMESniffing.cpp b/Source/WebKit/qt/tests/MIMESniffing/tst_MIMESniffing.cpp
new file mode 100644
index 0000000..8c5417f
--- /dev/null
+++ b/Source/WebKit/qt/tests/MIMESniffing/tst_MIMESniffing.cpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "MIMESniffing.h"
+
+#include "TestData.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QString>
+#include <QtTest/QtTest>
+
+class tst_MIMESniffing : public QObject {
+ Q_OBJECT
+
+public:
+ tst_MIMESniffing();
+
+private Q_SLOTS:
+ void testCase1();
+};
+
+tst_MIMESniffing::tst_MIMESniffing()
+{
+}
+
+static inline const char* errorText(const TestData& data, const char* sniffedType)
+{
+ return QString("file: %1, advertised: %2, image: %3. sniffed mime type was expected to be \"%4\" but instead was \"%5\"").arg(data.file).arg(data.advertisedType).arg(data.isImage).arg(data.sniffedType).arg(sniffedType).toLatin1();
+}
+
+void tst_MIMESniffing::testCase1()
+{
+
+ for (int i = 0; i < testListSize; ++i) {
+ QFile file(testList[i].file);
+ QVERIFY2(file.open(QIODevice::ReadOnly), QString("unable to open file %1").arg(file.fileName()).toLatin1());
+
+ MIMESniffer sniffer(testList[i].advertisedType, testList[i].isImage);
+ QByteArray data = file.peek(sniffer.dataSize());
+
+ const char* sniffedType = sniffer.sniff(data.constData(), data.size());
+
+ QVERIFY2(!(sniffedType || testList[i].sniffedType) || (sniffedType && testList[i].sniffedType), errorText(testList[i], sniffedType));
+
+ if (sniffedType)
+ QVERIFY2(!strcmp(sniffedType, testList[i].sniffedType), errorText(testList[i], sniffedType));
+
+ }
+
+ QVERIFY2(true, "Failure");
+}
+
+QTEST_APPLESS_MAIN(tst_MIMESniffing);
+
+#include "tst_MIMESniffing.moc"
diff --git a/Source/WebKit/qt/tests/benchmarks/loading/loading.pro b/Source/WebKit/qt/tests/benchmarks/loading/loading.pro
new file mode 100644
index 0000000..99c64a5
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/loading/loading.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../../..
+include(../../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/benchmarks/loading/tst_loading.cpp b/Source/WebKit/qt/tests/benchmarks/loading/tst_loading.cpp
new file mode 100644
index 0000000..0bc87f7
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/loading/tst_loading.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <QtTest/QtTest>
+
+#include <qwebframe.h>
+#include <qwebview.h>
+#include <qpainter.h>
+
+/**
+ * Starts an event loop that runs until the given signal is received.
+ Optionally the event loop
+ * can return earlier on a timeout.
+ *
+ * \return \p true if the requested signal was received
+ * \p false on timeout
+ */
+static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
+{
+ QEventLoop loop;
+ QObject::connect(obj, signal, &loop, SLOT(quit()));
+ QTimer timer;
+ QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
+ if (timeout > 0) {
+ QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ timer.setSingleShot(true);
+ timer.start(timeout);
+ }
+ loop.exec();
+ return timeoutSpy.isEmpty();
+}
+
+class tst_Loading : public QObject
+{
+ Q_OBJECT
+
+public:
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private Q_SLOTS:
+ void load_data();
+ void load();
+
+private:
+ QWebView* m_view;
+ QWebPage* m_page;
+};
+
+void tst_Loading::init()
+{
+ m_view = new QWebView;
+ m_page = m_view->page();
+
+ QSize viewportSize(1024, 768);
+ m_view->setFixedSize(viewportSize);
+ m_page->setViewportSize(viewportSize);
+}
+
+void tst_Loading::cleanup()
+{
+ delete m_view;
+}
+
+void tst_Loading::load_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::newRow("amazon") << QUrl("http://www.amazon.com");
+ QTest::newRow("kde") << QUrl("http://www.kde.org");
+ QTest::newRow("apple") << QUrl("http://www.apple.com");
+}
+
+void tst_Loading::load()
+{
+ QFETCH(QUrl, url);
+
+
+ QBENCHMARK {
+ m_view->load(url);
+
+ // really wait for loading, painting is in another test
+ ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
+ }
+}
+
+QTEST_MAIN(tst_Loading)
+#include "tst_loading.moc"
diff --git a/Source/WebKit/qt/tests/benchmarks/painting/painting.pro b/Source/WebKit/qt/tests/benchmarks/painting/painting.pro
new file mode 100644
index 0000000..99c64a5
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/painting/painting.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../../..
+include(../../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/benchmarks/painting/tst_painting.cpp b/Source/WebKit/qt/tests/benchmarks/painting/tst_painting.cpp
new file mode 100644
index 0000000..fc5b8e3
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/painting/tst_painting.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <QtTest/QtTest>
+
+#include <qwebelement.h>
+#include <qwebframe.h>
+#include <qwebview.h>
+#include <qpainter.h>
+
+/**
+ * Starts an event loop that runs until the given signal is received.
+ Optionally the event loop
+ * can return earlier on a timeout.
+ *
+ * \return \p true if the requested signal was received
+ * \p false on timeout
+ */
+static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
+{
+ QEventLoop loop;
+ QObject::connect(obj, signal, &loop, SLOT(quit()));
+ QTimer timer;
+ QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
+ if (timeout > 0) {
+ QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ timer.setSingleShot(true);
+ timer.start(timeout);
+ }
+ loop.exec();
+ return timeoutSpy.isEmpty();
+}
+
+class tst_Painting : public QObject
+{
+ Q_OBJECT
+
+public:
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private Q_SLOTS:
+ void paint_data();
+ void paint();
+ void textAreas();
+
+private:
+ QWebView* m_view;
+ QWebPage* m_page;
+};
+
+void tst_Painting::init()
+{
+ m_view = new QWebView;
+ m_page = m_view->page();
+
+ QSize viewportSize(1024, 768);
+ m_view->setFixedSize(viewportSize);
+ m_page->setViewportSize(viewportSize);
+}
+
+void tst_Painting::cleanup()
+{
+ delete m_view;
+}
+
+void tst_Painting::paint_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::newRow("amazon") << QUrl("http://www.amazon.com");
+}
+
+void tst_Painting::paint()
+{
+ QFETCH(QUrl, url);
+
+ m_view->load(url);
+ ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
+
+ /* force a layout */
+ QWebFrame* mainFrame = m_page->mainFrame();
+ mainFrame->toPlainText();
+
+ QPixmap pixmap(m_page->viewportSize());
+ QBENCHMARK {
+ QPainter painter(&pixmap);
+ mainFrame->render(&painter, QRect(QPoint(0, 0), m_page->viewportSize()));
+ painter.end();
+ }
+}
+
+void tst_Painting::textAreas()
+{
+ m_view->load(QUrl("data:text/html;<html><body></body></html>"));
+ ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
+
+ QWebElement bodyElement = m_page->mainFrame()->findFirstElement("body");
+
+ int count = 100;
+ while (count--) {
+ QString markup("<textarea cols='1' rows='1'></textarea>");
+ bodyElement.appendInside(markup);
+ }
+
+ /* force a layout */
+ QWebFrame* mainFrame = m_page->mainFrame();
+ mainFrame->toPlainText();
+
+ QPixmap pixmap(mainFrame->contentsSize());
+ QBENCHMARK {
+ QPainter painter(&pixmap);
+ mainFrame->render(&painter, QRect(QPoint(0, 0), mainFrame->contentsSize()));
+ painter.end();
+ }
+}
+
+QTEST_MAIN(tst_Painting)
+#include "tst_painting.moc"
diff --git a/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html b/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html
new file mode 100644
index 0000000..fd061aa
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html
@@ -0,0 +1,59 @@
+<html>
+ <body style="margin: 0">
+ <canvas width="1000" height="1000"></canvas>
+ </body>
+</html>
+<script>
+ var canvas = document.getElementsByTagName("canvas")[0];
+ gl = canvas.getContext("experimental-webgl");
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, "attribute vec4 vPosition;\nvoid main() { gl_Position = vPosition; }");
+ gl.compileShader(vertexShader);
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+ gl.compileShader(fragmentShader);
+
+ var shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.bindAttribLocation(shaderProgram, 0, "vPosition");
+ gl.linkProgram(shaderProgram);
+
+ gl.useProgram(shaderProgram);
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+ var vertices = [];
+ var seedX = -1.0;
+ var seedY = 1.0;
+ for (var i = 1; i <= 10000; ++i) {
+ vertices.push(seedX);
+ vertices.push(seedY);
+ vertices.push(0);
+ seedX += 0.01;
+ vertices.push(seedX);
+ vertices.push(seedY - 0.02);
+ vertices.push(0);
+ seedX += 0.01;
+ vertices.push(seedX);
+ vertices.push(seedY);
+ vertices.push(0);
+ if (!(i % 100)) {
+ seedX = -1.0;
+ seedY -= 0.02;
+ }
+ }
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+
+ gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 30000);
+ gl.flush();
+</script>
diff --git a/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp b/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp
new file mode 100644
index 0000000..bd865a2
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp
@@ -0,0 +1,130 @@
+/*
+ Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include "../../util.h"
+#include <QGLWidget>
+#include <QGraphicsView>
+#include <QGraphicsWebView>
+#include <QScopedPointer>
+#include <QWebFrame>
+#include <QtTest/QtTest>
+
+class GraphicsView;
+
+class tst_WebGlPerformance : public QObject {
+ Q_OBJECT
+
+private slots:
+ void init();
+ void cleanup();
+
+ void benchSoftwareFallbackRgb16();
+ void benchSoftwareFallbackRgb32();
+ void benchSoftwareFallbackArgb32();
+ void benchSoftwareFallbackArgb32Premultiplied();
+
+private:
+ void benchmarkFrameRenderingOnImage(QImage::Format);
+
+ QScopedPointer<GraphicsView> m_view;
+};
+
+class GraphicsView : public QGraphicsView {
+public:
+ GraphicsView();
+ QGraphicsWebView* m_webView;
+
+protected:
+ void resizeEvent(QResizeEvent*);
+};
+
+GraphicsView::GraphicsView()
+{
+ QGraphicsScene* const scene = new QGraphicsScene(this);
+ setScene(scene);
+
+ m_webView = new QGraphicsWebView;
+ scene->addItem(m_webView);
+
+ m_webView->page()->settings()->setAttribute(QWebSettings::WebGLEnabled, true);
+
+ resize(800, 600);
+ setFrameShape(QFrame::NoFrame);
+ setViewport(new QGLWidget);
+}
+
+void GraphicsView::resizeEvent(QResizeEvent* event)
+{
+ QGraphicsView::resizeEvent(event);
+ QRectF rect(QPoint(0, 0), event->size());
+ m_webView->setGeometry(rect);
+ scene()->setSceneRect(rect);
+}
+
+void tst_WebGlPerformance::init()
+{
+ m_view.reset(new GraphicsView);
+ m_view->showMaximized();
+ QTest::qWaitForWindowShown(m_view.data());
+}
+
+void tst_WebGlPerformance::cleanup()
+{
+ m_view.reset();
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackRgb16()
+{
+ benchmarkFrameRenderingOnImage(QImage::Format_RGB16);
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackRgb32()
+{
+ benchmarkFrameRenderingOnImage(QImage::Format_RGB32);
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackArgb32()
+{
+ benchmarkFrameRenderingOnImage(QImage::Format_ARGB32);
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackArgb32Premultiplied()
+{
+ benchmarkFrameRenderingOnImage(QImage::Format_ARGB32_Premultiplied);
+}
+
+void tst_WebGlPerformance::benchmarkFrameRenderingOnImage(QImage::Format format)
+{
+ m_view->m_webView->load(QUrl(QLatin1String("qrc:///testcases/10000_triangles.html")));
+ const bool pageLoaded = waitForSignal(m_view->m_webView, SIGNAL(loadFinished(bool)));
+ Q_ASSERT(pageLoaded);
+ Q_UNUSED(pageLoaded);
+
+ QImage target(m_view->size(), format);
+ QBENCHMARK {
+ QPainter painter(&target);
+ m_view->render(&painter);
+ painter.end();
+ }
+}
+
+QTEST_MAIN(tst_WebGlPerformance)
+
+#include "tst_webgl.moc"
diff --git a/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc b/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc
new file mode 100644
index 0000000..b849448
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/testcases">
+ <file>10000_triangles.html</file>
+ </qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro b/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro
new file mode 100644
index 0000000..fb21bc8
--- /dev/null
+++ b/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro
@@ -0,0 +1,4 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../../..
+include(../../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
+QT += opengl
diff --git a/Source/WebKit/qt/tests/hybridPixmap/hybridPixmap.pro b/Source/WebKit/qt/tests/hybridPixmap/hybridPixmap.pro
new file mode 100644
index 0000000..9e80870
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/hybridPixmap.pro
@@ -0,0 +1,11 @@
+# -------------------------------------------------
+# Project created by QtCreator 2009-12-10T11:25:02
+# -------------------------------------------------
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+TARGET = hybridPixmap
+SOURCES += widget.cpp
+HEADERS += widget.h
+FORMS += widget.ui
+RESOURCES += resources.qrc
+CONFIG += console
diff --git a/Source/WebKit/qt/tests/hybridPixmap/resources.qrc b/Source/WebKit/qt/tests/hybridPixmap/resources.qrc
new file mode 100644
index 0000000..5fd47e3
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/resources.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>test.html</file>
+ </qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/hybridPixmap/test.html b/Source/WebKit/qt/tests/hybridPixmap/test.html
new file mode 100644
index 0000000..0f2c345
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/test.html
@@ -0,0 +1,65 @@
+<html>
+ <head>
+ <style>
+ img { display: block; border-style: groove}
+ </style>
+ <script>
+ function startTest()
+ {
+ var obj = myWidget.image;
+ var pxm = myWidget.pixmap;
+
+ var img = new Image;
+ obj.assignToHTMLImageElement(img);
+ var img1 = document.getElementById("img1");
+ var img2 = document.getElementById("img2");
+ var img3 = document.getElementById("img3");
+ var img4 = document.getElementById("img4");
+ document.body.appendChild(img);
+ obj.assignToHTMLImageElement(img3);
+ pxm.assignToHTMLImageElement(img4);
+ myWidget.compare(pxm.width, img4.width);
+ myWidget.compare(obj.width, img3.width);
+ var signalsFired = 0;
+ myWidget.compare(obj.toString(),"[Qt Native Pixmap "+obj.width+","+obj.height+"]");
+ myWidget.compare(String(pxm),"[Qt Native Pixmap "+pxm.width+","+pxm.height+"]");
+
+ // this shouldn't work but shouldn't crash
+ myWidget.randomSlot("foobar");
+
+ myWidget.pixmapSignal.connect(function(imgFromSignal) {
+ myWidget.compare(imgFromSignal.height, img2.height);
+ if (++signalsFired == 2)
+ myWidget.completeTest();
+ });
+
+ myWidget.imageSignal.connect(function(imgFromSignal) {
+ myWidget.compare(pxm.height, img2.height);
+ if (++signalsFired == 2)
+ myWidget.completeTest();
+ });
+
+ function continueTestAfterImagesAreLoaded()
+ {
+ if (img1.complete && img2.complete) {
+ myWidget.compare(pxm.height, img2.height);
+ myWidget.pixmapSlot(img);
+ myWidget.imageSlot(pxm);
+ }
+ }
+ img1.onload = continueTestAfterImagesAreLoaded;
+ img2.onload = continueTestAfterImagesAreLoaded;
+ img1.src = obj.toDataUrl();
+ img2.src = myWidget.pixmap.toDataUrl();
+ myWidget.image = pxm;
+ myWidget.pixmap = img;
+ }
+ </script>
+ </head>
+ <body onload="startTest()">
+ <img id="img1" />
+ <img id="img2" />
+ <img id="img3" />
+ <img id="img4" />
+ </body>
+</html>
diff --git a/Source/WebKit/qt/tests/hybridPixmap/tst_hybridPixmap.cpp b/Source/WebKit/qt/tests/hybridPixmap/tst_hybridPixmap.cpp
new file mode 100644
index 0000000..72dbb3b
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/tst_hybridPixmap.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "../util.h"
+
+#include "widget.h"
+#include <QtTest/QtTest>
+
+class tst_hybridPixmap : public QObject {
+ Q_OBJECT
+
+public:
+ tst_hybridPixmap(QObject* o = 0) : QObject(o) {}
+
+public slots:
+ void init()
+ {
+ }
+
+ void cleanup()
+ {
+ }
+
+private slots:
+ void hybridPixmap()
+ {
+ Widget widget;
+ widget.show();
+ widget.start();
+ waitForSignal(&widget, SIGNAL(testComplete()));
+ }
+};
+
+QTEST_MAIN(tst_hybridPixmap)
+
+#include <tst_hybridPixmap.moc>
diff --git a/Source/WebKit/qt/tests/hybridPixmap/widget.cpp b/Source/WebKit/qt/tests/hybridPixmap/widget.cpp
new file mode 100644
index 0000000..cfdb1d6
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/widget.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "widget.h"
+
+#include "qwebelement.h"
+#include "qwebframe.h"
+#include "ui_widget.h"
+#include <QPainter>
+#include <QtTest/QtTest>
+
+Widget::Widget(QWidget* parent) :
+ QWidget(parent),
+ ui(new Ui::Widget)
+{
+ ui->setupUi(this);
+}
+
+void Widget::refreshJS()
+{
+ ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("myWidget", this);
+}
+void Widget::start()
+{
+ ui->webView->load(QUrl("qrc:///test.html"));
+ connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(refreshJS()));
+ ui->webView->page()->mainFrame()->addToJavaScriptWindowObject("myWidget", this);
+}
+
+void Widget::completeTest()
+{
+ QCOMPARE(ui->lbl1->pixmap()->size(), ui->lbl2->size());
+ QCOMPARE(ui->lbl3->size(), ui->lbl4->pixmap()->size());
+ QCOMPARE(ui->lbl2->size().width(), ui->webView->page()->mainFrame()->findFirstElement("#img1").evaluateJavaScript("this.width").toInt());
+ QCOMPARE(ui->lbl3->size().width(), ui->webView->page()->mainFrame()->findFirstElement("#img2").evaluateJavaScript("this.width").toInt());
+ emit testComplete();
+}
+
+void Widget::setPixmap(const QPixmap& p)
+{
+ ui->lbl1->setPixmap(p);
+}
+QPixmap Widget::pixmap() const
+{
+ QPixmap px(ui->lbl3->size());
+ {
+ QPainter p(&px);
+ ui->lbl3->render(&p);
+ }
+ return px;
+}
+void Widget::setImage(const QImage& img)
+{
+ ui->lbl4->setPixmap(QPixmap::fromImage(img));
+}
+
+QImage Widget::image() const
+{
+ QImage img(ui->lbl2->size(), QImage::Format_ARGB32);
+ {
+ QPainter p(&img);
+ ui->lbl2->render(&p);
+ }
+ return img;
+}
+
+Widget::~Widget()
+{
+ delete ui;
+}
+
+void Widget::changeEvent(QEvent* e)
+{
+ QWidget::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+void Widget::compare(const QVariant& a, const QVariant& b)
+{
+ QCOMPARE(a, b);
+}
+
+void Widget::imageSlot(const QImage& img)
+{
+ QCOMPARE(img.size(), ui->lbl3->size());
+ emit pixmapSignal(QPixmap::fromImage(img));
+}
+
+void Widget::pixmapSlot(const QPixmap& pxm)
+{
+ QCOMPARE(pxm.size(), ui->lbl2->size());
+ emit imageSignal(ui->lbl4->pixmap()->toImage());
+}
+
+void Widget::randomSlot(const QPixmap& pxm)
+{
+ QVERIFY(pxm.isNull());
+}
diff --git a/Source/WebKit/qt/tests/hybridPixmap/widget.h b/Source/WebKit/qt/tests/hybridPixmap/widget.h
new file mode 100644
index 0000000..2ac8a06
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/widget.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef widget_h
+#define widget_h
+
+#include <QImage>
+#include <QPixmap>
+#include <QWidget>
+#include "qwebview.h"
+
+typedef QWebView WebView;
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class Widget;
+}
+QT_END_NAMESPACE
+
+class Widget : public QWidget {
+ Q_OBJECT
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)
+ Q_PROPERTY(QImage image READ image WRITE setImage)
+
+public:
+ Widget(QWidget* parent = 0);
+ ~Widget();
+ void setPixmap(const QPixmap&);
+ QPixmap pixmap() const;
+ void setImage(const QImage&);
+ QImage image() const;
+
+private slots:
+ void refreshJS();
+
+public slots:
+ void completeTest();
+ void start();
+ void compare(const QVariant& a, const QVariant& b);
+ void imageSlot(const QImage&);
+ void pixmapSlot(const QPixmap&);
+ void randomSlot(const QPixmap&);
+
+signals:
+ void testComplete();
+ void imageSignal(const QImage&);
+ void pixmapSignal(const QPixmap&);
+
+protected:
+ void changeEvent(QEvent* e);
+
+private:
+ Ui::Widget* ui;
+};
+
+#endif // widget_h
diff --git a/Source/WebKit/qt/tests/hybridPixmap/widget.ui b/Source/WebKit/qt/tests/hybridPixmap/widget.ui
new file mode 100644
index 0000000..272d6a7
--- /dev/null
+++ b/Source/WebKit/qt/tests/hybridPixmap/widget.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="QWidget" name="Widget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>400</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Widget</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="WebView" name="webView" native="true">
+ <property name="url" stdset="0">
+ <url>
+ <string notr="true">about:blank</string>
+ </url>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="lbl1">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lbl2">
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>120</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string notr="true">Image from Qt to HTML</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lbl3">
+ <property name="text">
+ <string notr="true">Pixmap from Qt to HTML</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lbl4">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <customwidgets>
+ <customwidget>
+ <class>WebView</class>
+ <extends>QWidget</extends>
+ <header>widget.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/qdeclarativewebview.pro b/Source/WebKit/qt/tests/qdeclarativewebview/qdeclarativewebview.pro
new file mode 100644
index 0000000..488fa84
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/qdeclarativewebview.pro
@@ -0,0 +1,6 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
+INCLUDEPATH += \
+ $$PWD/../../declarative
+
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.html b/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.html
new file mode 100644
index 0000000..22e3e24
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.html
@@ -0,0 +1,17 @@
+<html>
+<head><title>Basic</title>
+<link rel="icon" sizes="48x48" href="basic.png">
+<script type="text/javascript">
+<!--
+window.onload = function(){ window.status = "status here"; }
+// -->
+</script>
+</head>
+<body leftmargin="0" marginwidth="0">
+<table width="123">
+<tbody>
+<tr><td>This is a basic test.</td></tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.png b/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.png
new file mode 100644
index 0000000..35717cc
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.png
Binary files differ
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.qml
new file mode 100644
index 0000000..b5208d0
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/basic.qml
@@ -0,0 +1,5 @@
+import QtWebKit 1.0
+
+WebView {
+ url: "basic.html"
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.html b/Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.html
new file mode 100644
index 0000000..9236867
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.html
@@ -0,0 +1,14 @@
+<body leftmargin=0 topmargin=0>
+<table width="300px" border=1 cellpadding=0 cellspacing=0>
+<tr>
+<td align=center width=25%%><p>A</p></td>
+<td width=75% height=50px>
+ <table width=100% border=1 cellpadding=0 cellspacing=0>
+ <tr>
+ <td align=center width=50% height=50px><p>B</p></td>
+ <td align=center width=50% height=50px><p>C</p></td>
+ </tr>
+ </table>
+</td>
+</tr>
+</table>
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.qml
new file mode 100644
index 0000000..8fef8c9
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/elements.qml
@@ -0,0 +1,7 @@
+import QtWebKit 1.0
+
+WebView {
+ url: "elements.html"
+ width: 310
+ height: 100
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.html b/Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.html
new file mode 100644
index 0000000..62ab62d
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.html
@@ -0,0 +1,12 @@
+<html>
+<head><title>Forward</title>
+<link rel="icon" sizes="32x32" href="forward.png">
+</head>
+<body leftmargin="0" marginwidth="0">
+<table width="123">
+<tbody>
+<tr><td>This is more.</td></tr>
+</tbody>
+</table>
+</body>
+</html>
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.png b/Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.png
new file mode 100644
index 0000000..a82533e
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/forward.png
Binary files differ
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.html b/Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.html
new file mode 100644
index 0000000..35270bc
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.html
@@ -0,0 +1,11 @@
+<html>
+<head><title>JavaScript</title>
+<link rel="icon" sizes="48x48" href="basic.png">
+<script type="text/javascript">
+<!--
+window.onload = function(){ window.status = "status here"; }
+// -->
+</script>
+</head>
+<body>
+This is a JS test.
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.qml
new file mode 100644
index 0000000..527e3b9
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/javaScript.qml
@@ -0,0 +1,12 @@
+import QtQuick 1.0
+import QtWebKit 1.0
+
+WebView {
+ url: "javaScript.html"
+ javaScriptWindowObjects: [
+ QtObject {
+ property string qmlprop: "qmlvalue"
+ WebView.windowObjectName: "myjsname"
+ }
+ ]
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/loadError.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/loadError.qml
new file mode 100644
index 0000000..26cec8f
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/loadError.qml
@@ -0,0 +1,5 @@
+import QtWebKit 1.0
+
+WebView {
+ url: "does-not-exist.html"
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.html b/Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.html
new file mode 100644
index 0000000..dd541f9
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<script type="text/javascript">
+<!--
+function clickTheLink()
+{
+ var ev = document.createEvent('MouseEvents');
+ ev.initEvent( "click", true, false );
+ document.getElementById('thelink').dispatchEvent(ev);
+}
+// -->
+</script>
+</head>
+<h1>Multiple windows...</h1>
+
+<a id=thelink target="_blank" href="newwindows.html">Popup!</a>
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.qml
new file mode 100644
index 0000000..e66631d
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/newwindows.qml
@@ -0,0 +1,34 @@
+// Demonstrates opening new WebViews from HTML
+
+import QtQuick 1.0
+import QtWebKit 1.0
+
+Grid {
+ columns: 3
+ id: pages
+ height: 300; width: 600
+ property int total: 0
+
+ Component {
+ id: webViewPage
+ Rectangle {
+ width: webView.width
+ height: webView.height
+ border.color: "gray"
+
+ WebView {
+ id: webView
+ width: 150 // force predictable for test
+ newWindowComponent: webViewPage
+ newWindowParent: pages
+ url: "newwindows.html"
+ Timer {
+ interval: 10; running: total<4; repeat: false;
+ onTriggered: { if (webView.status==WebView.Ready) { total++; webView.evaluateJavaScript("clickTheLink()") } }
+ }
+ }
+ }
+ }
+
+ Loader { sourceComponent: webViewPage }
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/propertychanges.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/propertychanges.qml
new file mode 100644
index 0000000..db06887
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/propertychanges.qml
@@ -0,0 +1,34 @@
+import QtQuick 1.0
+import QtWebKit 1.0
+
+Item {
+ width: 240
+ height: 160
+ Grid {
+ anchors.fill: parent
+ objectName: "newWindowParent"
+ id: newWindowParent
+ }
+
+ Row {
+ anchors.fill: parent
+ id: oldWindowParent
+ objectName: "oldWindowParent"
+ }
+
+ Loader {
+ sourceComponent: webViewComponent
+ }
+ Component {
+ id: webViewComponent
+ WebView {
+ id: webView
+ objectName: "webView"
+ newWindowComponent: webViewComponent
+ newWindowParent: oldWindowParent
+ url: "basic.html"
+ renderingEnabled: true
+ pressGrabTime: 200
+ }
+ }
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/sample.html b/Source/WebKit/qt/tests/qdeclarativewebview/resources/sample.html
new file mode 100644
index 0000000..cc9bffa
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/sample.html
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body width=400 height=400>
+Here is a sample text
+</body>
+</html>
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/sethtml.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/sethtml.qml
new file mode 100644
index 0000000..5bff442
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/sethtml.qml
@@ -0,0 +1,5 @@
+import QtWebKit 1.0
+
+WebView {
+ html: "<p>This is a <b>string</b> set on the WebView"
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewbackgroundcolor.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewbackgroundcolor.qml
new file mode 100644
index 0000000..2edc794
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewbackgroundcolor.qml
@@ -0,0 +1,10 @@
+import Qt 4.7
+import QtWebKit 1.1
+
+WebView {
+ id: myweb
+ height: 300
+ width: 300
+ focus: true
+ backgroundColor : "red"
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtest.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtest.qml
new file mode 100644
index 0000000..ae8a42b
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtest.qml
@@ -0,0 +1,24 @@
+import Qt 4.7
+import QtWebKit 1.0
+
+Flickable {
+ id: flick
+ width: 640
+ height: 400
+ clip: true
+ contentWidth: myweb.width; contentHeight: myweb.height
+ property alias myurl: myweb.url
+ property alias prefHeight: myweb.preferredHeight
+ property alias prefWidth: myweb.preferredWidth
+ property url testUrl;
+ WebView {
+ id: myweb
+ url: testUrl
+ smooth: false
+ scale: 1.0
+ preferredHeight: 500
+ preferredWidth: 600
+ pressGrabTime: 1000
+ focus: true
+ }
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtestdefault.qml b/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtestdefault.qml
new file mode 100644
index 0000000..3f659f6
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/resources/webviewtestdefault.qml
@@ -0,0 +1,22 @@
+import Qt 4.7
+import QtWebKit 1.0
+
+Flickable {
+ id: flick
+ width: 640
+ height: 400
+ clip: true
+ contentWidth: myweb.width; contentHeight: myweb.height
+ property alias myurl: myweb.url
+ property alias prefHeight: myweb.preferredHeight
+ property alias prefWidth: myweb.preferredWidth
+ property url testUrl;
+ WebView {
+ id: myweb
+ url: testUrl;
+ smooth: false
+ scale: 1.0
+ pressGrabTime: 1000
+ focus: true
+ }
+}
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp b/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp
new file mode 100644
index 0000000..23e8bfb
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.cpp
@@ -0,0 +1,544 @@
+#include "../util.h"
+#include <QAction>
+#include <QColor>
+#include <QDebug>
+#include <QDeclarativeComponent>
+#include <QDeclarativeEngine>
+#include <QDeclarativeItem>
+#include <QDeclarativeProperty>
+#include <QDeclarativeView>
+#include <QDir>
+#include <QGraphicsWebView>
+#include <QTest>
+#include <QVariant>
+#include <QWebFrame>
+#include "qdeclarativewebview_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class tst_QDeclarativeWebView : public QObject {
+ Q_OBJECT
+
+public:
+ tst_QDeclarativeWebView();
+
+private slots:
+ void cleanupTestCase();
+
+ void basicProperties();
+ void elementAreaAt();
+ void historyNav();
+ void javaScript();
+ void loadError();
+ void multipleWindows();
+ void newWindowComponent();
+ void newWindowParent();
+ void preferredWidthTest();
+ void preferredHeightTest();
+ void preferredWidthDefaultTest();
+ void preferredHeightDefaultTest();
+ void pressGrabTime();
+ void renderingEnabled();
+ void setHtml();
+ void settings();
+#if QT_VERSION >= 0x040703
+ void backgroundColor();
+#endif
+
+private:
+ void checkNoErrors(const QDeclarativeComponent&);
+ QString tmpDir() const
+ {
+ static QString tmpd = QDir::tempPath() + "/tst_qdeclarativewebview-"
+ + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss"));
+ return tmpd;
+ }
+};
+
+tst_QDeclarativeWebView::tst_QDeclarativeWebView()
+{
+ Q_UNUSED(waitForSignal)
+}
+
+static QString strippedHtml(QString html)
+{
+ html.replace(QRegExp("\\s+"), "");
+ return html;
+}
+
+static QString fileContents(const QString& filename)
+{
+ QFile file(filename);
+ file.open(QIODevice::ReadOnly);
+ return QString::fromUtf8(file.readAll());
+}
+
+static void removeRecursive(const QString& dirname)
+{
+ QDir dir(dirname);
+ QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot));
+ for (int i = 0; i < entries.count(); ++i)
+ if (entries[i].isDir())
+ removeRecursive(entries[i].filePath());
+ else
+ dir.remove(entries[i].fileName());
+ QDir().rmdir(dirname);
+}
+
+void tst_QDeclarativeWebView::cleanupTestCase()
+{
+ removeRecursive(tmpDir());
+}
+
+void tst_QDeclarativeWebView::basicProperties()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/basic.qml"));
+ checkNoErrors(component);
+ QWebSettings::enablePersistentStorage(tmpDir());
+
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+ QCOMPARE(wv->property("title").toString(), QLatin1String("Basic"));
+ QTRY_COMPARE(qvariant_cast<QPixmap>(wv->property("icon")).width(), 48);
+ QEXPECT_FAIL("", "'icon' property isn't working", Continue);
+ QCOMPARE(qvariant_cast<QPixmap>(wv->property("icon")), QPixmap("qrc:///resources/basic.png"));
+ QCOMPARE(wv->property("statusText").toString(), QLatin1String("status here"));
+ QCOMPARE(strippedHtml(fileContents(":/resources/basic.html")), strippedHtml(wv->property("html").toString()));
+ QEXPECT_FAIL("", "TODO: get preferred width from QGraphicsWebView result", Continue);
+ QCOMPARE(wv->property("preferredWidth").toInt(), 0);
+ QEXPECT_FAIL("", "TODO: get preferred height from QGraphicsWebView result", Continue);
+ QCOMPARE(wv->property("preferredHeight").toInt(), 0);
+ QCOMPARE(wv->property("url").toUrl(), QUrl("qrc:///resources/basic.html"));
+ QCOMPARE(wv->property("status").toInt(), int(QDeclarativeWebView::Ready));
+
+ QAction* reloadAction = wv->property("reload").value<QAction*>();
+ QVERIFY(reloadAction);
+ QVERIFY(reloadAction->isEnabled());
+ QAction* backAction = wv->property("back").value<QAction*>();
+ QVERIFY(backAction);
+ QVERIFY(!backAction->isEnabled());
+ QAction* forwardAction = wv->property("forward").value<QAction*>();
+ QVERIFY(forwardAction);
+ QVERIFY(!forwardAction->isEnabled());
+ QAction* stopAction = wv->property("stop").value<QAction*>();
+ QVERIFY(stopAction);
+ QVERIFY(!stopAction->isEnabled());
+
+ wv->setProperty("pixelCacheSize", 0); // mainly testing that it doesn't crash or anything!
+ QCOMPARE(wv->property("pixelCacheSize").toInt(), 0);
+ reloadAction->trigger();
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+}
+
+void tst_QDeclarativeWebView::elementAreaAt()
+{
+ QSKIP("This test should be changed to test 'heuristicZoom' instead.", SkipAll);
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/elements.qml"));
+ checkNoErrors(component);
+ QDeclarativeWebView* wv = qobject_cast<QDeclarativeWebView*>(component.create());
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+
+ // Areas from elements.html.
+// const QRect areaA(1, 1, 75, 54);
+// const QRect areaB(78, 3, 110, 50);
+// const QRect wholeView(0, 0, 310, 100);
+// const QRect areaBC(76, 1, 223, 54);
+
+// QCOMPARE(wv->elementAreaAt(40, 30, 100, 100), areaA);
+// QCOMPARE(wv->elementAreaAt(130, 30, 200, 100), areaB);
+// QCOMPARE(wv->elementAreaAt(40, 30, 400, 400), wholeView);
+// QCOMPARE(wv->elementAreaAt(130, 30, 280, 280), areaBC);
+// QCOMPARE(wv->elementAreaAt(130, 30, 400, 400), wholeView);
+}
+
+void tst_QDeclarativeWebView::historyNav()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/basic.qml"));
+ checkNoErrors(component);
+ QWebSettings::enablePersistentStorage(tmpDir());
+
+ QObject* wv = component.create();
+ QVERIFY(wv);
+
+ QAction* reloadAction = wv->property("reload").value<QAction*>();
+ QVERIFY(reloadAction);
+ QAction* backAction = wv->property("back").value<QAction*>();
+ QVERIFY(backAction);
+ QAction* forwardAction = wv->property("forward").value<QAction*>();
+ QVERIFY(forwardAction);
+ QAction* stopAction = wv->property("stop").value<QAction*>();
+ QVERIFY(stopAction);
+
+ for (int i = 1; i <= 2; ++i) {
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+ QCOMPARE(wv->property("title").toString(), QLatin1String("Basic"));
+ QTRY_COMPARE(qvariant_cast<QPixmap>(wv->property("icon")).width(), 48);
+ QEXPECT_FAIL("", "'icon' property isn't working", Continue);
+ QCOMPARE(qvariant_cast<QPixmap>(wv->property("icon")), QPixmap("qrc:///data/basic.png"));
+ QCOMPARE(wv->property("statusText").toString(), QLatin1String("status here"));
+ QCOMPARE(strippedHtml(fileContents(":/resources/basic.html")), strippedHtml(wv->property("html").toString()));
+ QEXPECT_FAIL("", "TODO: get preferred width from QGraphicsWebView result", Continue);
+ QCOMPARE(wv->property("preferredWidth").toDouble(), 0.0);
+ QCOMPARE(wv->property("url").toUrl(), QUrl("qrc:///resources/basic.html"));
+ QCOMPARE(wv->property("status").toInt(), int(QDeclarativeWebView::Ready));
+ QVERIFY(reloadAction->isEnabled());
+ QVERIFY(!backAction->isEnabled());
+ QVERIFY(!forwardAction->isEnabled());
+ QVERIFY(!stopAction->isEnabled());
+ reloadAction->trigger();
+ }
+
+ wv->setProperty("url", QUrl("qrc:///resources/forward.html"));
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+ QCOMPARE(wv->property("title").toString(), QLatin1String("Forward"));
+ QTRY_COMPARE(qvariant_cast<QPixmap>(wv->property("icon")).width(), 32);
+ QEXPECT_FAIL("", "'icon' property isn't working", Continue);
+ QCOMPARE(qvariant_cast<QPixmap>(wv->property("icon")), QPixmap("qrc:///resources/forward.png"));
+ QCOMPARE(strippedHtml(fileContents(":/resources/forward.html")), strippedHtml(wv->property("html").toString()));
+ QCOMPARE(wv->property("url").toUrl(), QUrl("qrc:///resources/forward.html"));
+ QCOMPARE(wv->property("status").toInt(), int(QDeclarativeWebView::Ready));
+ QCOMPARE(wv->property("statusText").toString(), QString());
+
+ QVERIFY(reloadAction->isEnabled());
+ QVERIFY(backAction->isEnabled());
+ QVERIFY(!forwardAction->isEnabled());
+ QVERIFY(!stopAction->isEnabled());
+
+ backAction->trigger();
+
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+ QCOMPARE(wv->property("title").toString(), QLatin1String("Basic"));
+ QCOMPARE(strippedHtml(fileContents(":/resources/basic.html")), strippedHtml(wv->property("html").toString()));
+ QCOMPARE(wv->property("url").toUrl(), QUrl("qrc:///resources/basic.html"));
+ QCOMPARE(wv->property("status").toInt(), int(QDeclarativeWebView::Ready));
+
+ QVERIFY(reloadAction->isEnabled());
+ QVERIFY(!backAction->isEnabled());
+ QVERIFY(forwardAction->isEnabled());
+ QVERIFY(!stopAction->isEnabled());
+}
+
+static inline QVariant callEvaluateJavaScript(QObject *object, const QString& snippet)
+{
+ QVariant result;
+ QMetaObject::invokeMethod(object, "evaluateJavaScript", Q_RETURN_ARG(QVariant, result), Q_ARG(QString, snippet));
+ return result;
+}
+
+void tst_QDeclarativeWebView::javaScript()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/javaScript.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+
+ QCOMPARE(callEvaluateJavaScript(wv, "123").toInt(), 123);
+ QCOMPARE(callEvaluateJavaScript(wv, "window.status").toString(), QLatin1String("status here"));
+ QCOMPARE(callEvaluateJavaScript(wv, "window.myjsname.qmlprop").toString(), QLatin1String("qmlvalue"));
+}
+
+void tst_QDeclarativeWebView::loadError()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/loadError.qml"));
+ checkNoErrors(component);
+ QWebSettings::enablePersistentStorage(tmpDir());
+
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ QAction* reloadAction = wv->property("reload").value<QAction*>();
+ QVERIFY(reloadAction);
+
+ for (int i = 1; i <= 2; ++i) {
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+ QCOMPARE(wv->property("title").toString(), QString());
+ QCOMPARE(wv->property("statusText").toString(), QString()); // HTML 'status bar' text, not error message
+ QCOMPARE(wv->property("url").toUrl(), QUrl("qrc:///resources/does-not-exist.html")); // Unlike QWebPage, which loses url
+ QCOMPARE(wv->property("status").toInt(), int(QDeclarativeWebView::Error));
+ reloadAction->trigger();
+ }
+}
+
+void tst_QDeclarativeWebView::multipleWindows()
+{
+ QSKIP("Rework this test to not depend on QDeclarativeGrid", SkipAll);
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/newwindows.qml"));
+ checkNoErrors(component);
+
+// QDeclarativeGrid *grid = qobject_cast<QDeclarativeGrid*>(component.create());
+// QVERIFY(grid != 0);
+// QTRY_COMPARE(grid->children().count(), 2+4); // Component, Loader (with 1 WebView), 4 new-window WebViews
+// QDeclarativeItem* popup = qobject_cast<QDeclarativeItem*>(grid->children().at(2)); // first popup after Component and Loader.
+// QVERIFY(popup != 0);
+// QTRY_COMPARE(popup->x(), 150.0);
+}
+
+void tst_QDeclarativeWebView::newWindowComponent()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/propertychanges.qml"));
+ checkNoErrors(component);
+ QDeclarativeItem* rootItem = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(rootItem);
+ QObject* wv = rootItem->findChild<QObject*>("webView");
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+
+ QDeclarativeComponent substituteComponent(&engine);
+ substituteComponent.setData("import QtQuick 1.0; WebView { objectName: 'newWebView'; url: 'basic.html'; }", QUrl::fromLocalFile(""));
+ QSignalSpy newWindowComponentSpy(wv, SIGNAL(newWindowComponentChanged()));
+
+ wv->setProperty("newWindowComponent", QVariant::fromValue(&substituteComponent));
+ QCOMPARE(wv->property("newWindowComponent"), QVariant::fromValue(&substituteComponent));
+ QCOMPARE(newWindowComponentSpy.count(), 1);
+
+ wv->setProperty("newWindowComponent", QVariant::fromValue(&substituteComponent));
+ QCOMPARE(newWindowComponentSpy.count(), 1);
+
+ wv->setProperty("newWindowComponent", QVariant::fromValue((QDeclarativeComponent*)0));
+ QCOMPARE(newWindowComponentSpy.count(), 2);
+}
+
+void tst_QDeclarativeWebView::newWindowParent()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/propertychanges.qml"));
+ checkNoErrors(component);
+ QDeclarativeItem* rootItem = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(rootItem);
+ QObject* wv = rootItem->findChild<QObject*>("webView");
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+
+ QDeclarativeItem* oldWindowParent = rootItem->findChild<QDeclarativeItem*>("oldWindowParent");
+ QCOMPARE(qvariant_cast<QDeclarativeItem*>(wv->property("newWindowParent")), oldWindowParent);
+ QSignalSpy newWindowParentSpy(wv, SIGNAL(newWindowParentChanged()));
+
+ QDeclarativeItem* newWindowParent = rootItem->findChild<QDeclarativeItem*>("newWindowParent");
+ wv->setProperty("newWindowParent", QVariant::fromValue(newWindowParent));
+ QVERIFY(newWindowParent);
+ QVERIFY(oldWindowParent);
+ QCOMPARE(oldWindowParent->childItems().count(), 0);
+ QCOMPARE(wv->property("newWindowParent"), QVariant::fromValue(newWindowParent));
+ QCOMPARE(newWindowParentSpy.count(), 1);
+
+ wv->setProperty("newWindowParent", QVariant::fromValue(newWindowParent));
+ QCOMPARE(newWindowParentSpy.count(), 1);
+
+ wv->setProperty("newWindowParent", QVariant::fromValue((QDeclarativeItem*)0));
+ QCOMPARE(newWindowParentSpy.count(), 2);
+}
+
+void tst_QDeclarativeWebView::preferredWidthTest()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/webviewtest.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ wv->setProperty("testUrl", QUrl("qrc:///resources/sample.html"));
+ QCOMPARE(wv->property("prefWidth").toInt(), 600);
+}
+
+void tst_QDeclarativeWebView::preferredHeightTest()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/webviewtest.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ wv->setProperty("testUrl", QUrl("qrc:///resources/sample.html"));
+ QCOMPARE(wv->property("prefHeight").toInt(), 500);
+}
+
+void tst_QDeclarativeWebView::preferredWidthDefaultTest()
+{
+ QGraphicsWebView view;
+ view.load(QUrl("qrc:///resources/sample.html"));
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/webviewtestdefault.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ wv->setProperty("testUrl", QUrl("qrc:///resources/sample.html"));
+ QCOMPARE(wv->property("prefWidth").toDouble(), view.preferredWidth());
+}
+
+void tst_QDeclarativeWebView::preferredHeightDefaultTest()
+{
+ QGraphicsWebView view;
+ view.load(QUrl("qrc:///resources/sample.html"));
+
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/webviewtestdefault.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ wv->setProperty("testUrl", QUrl("qrc:///resources/sample.html"));
+ QCOMPARE(wv->property("prefHeight").toDouble(), view.preferredHeight());
+}
+
+void tst_QDeclarativeWebView::pressGrabTime()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/propertychanges.qml"));
+ checkNoErrors(component);
+ QDeclarativeItem* rootItem = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(rootItem);
+ QObject* wv = rootItem->findChild<QObject*>("webView");
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+ QCOMPARE(wv->property("pressGrabTime").toInt(), 200);
+ QSignalSpy pressGrabTimeSpy(wv, SIGNAL(pressGrabTimeChanged()));
+
+ wv->setProperty("pressGrabTime", 100);
+ QCOMPARE(wv->property("pressGrabTime").toInt(), 100);
+ QCOMPARE(pressGrabTimeSpy.count(), 1);
+
+ wv->setProperty("pressGrabTime", 100);
+ QCOMPARE(pressGrabTimeSpy.count(), 1);
+
+ wv->setProperty("pressGrabTime", 0);
+ QCOMPARE(pressGrabTimeSpy.count(), 2);
+}
+
+void tst_QDeclarativeWebView::renderingEnabled()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/propertychanges.qml"));
+ checkNoErrors(component);
+ QDeclarativeItem* rootItem = qobject_cast<QDeclarativeItem*>(component.create());
+ QVERIFY(rootItem);
+ QObject* wv = rootItem->findChild<QObject*>("webView");
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+
+ QVERIFY(wv->property("renderingEnabled").toBool());
+ QSignalSpy renderingEnabledSpy(wv, SIGNAL(renderingEnabledChanged()));
+
+ wv->setProperty("renderingEnabled", false);
+ QVERIFY(!wv->property("renderingEnabled").toBool());
+ QCOMPARE(renderingEnabledSpy.count(), 1);
+
+ wv->setProperty("renderingEnabled", false);
+ QCOMPARE(renderingEnabledSpy.count(), 1);
+
+ wv->setProperty("renderingEnabled", true);
+ QCOMPARE(renderingEnabledSpy.count(), 2);
+}
+
+void tst_QDeclarativeWebView::setHtml()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/sethtml.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ QCOMPARE(wv->property("html").toString(), QLatin1String("<html><head></head><body><p>This is a <b>string</b> set on the WebView</p></body></html>"));
+
+ QSignalSpy spy(wv, SIGNAL(htmlChanged()));
+ wv->setProperty("html", QLatin1String("<html><head><title>Basic</title></head><body><p>text</p></body></html>"));
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QDeclarativeWebView::settings()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/basic.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ QTRY_COMPARE(wv->property("progress").toDouble(), 1.0);
+
+ QObject* s = QDeclarativeProperty(wv, "settings").object();
+ QVERIFY(s);
+
+ QStringList settingsList;
+ settingsList << QString::fromAscii("autoLoadImages")
+ << QString::fromAscii("developerExtrasEnabled")
+ << QString::fromAscii("javaEnabled")
+ << QString::fromAscii("javascriptCanAccessClipboard")
+ << QString::fromAscii("javascriptCanOpenWindows")
+ << QString::fromAscii("javascriptEnabled")
+ << QString::fromAscii("linksIncludedInFocusChain")
+ << QString::fromAscii("localContentCanAccessRemoteUrls")
+ << QString::fromAscii("localStorageDatabaseEnabled")
+ << QString::fromAscii("offlineStorageDatabaseEnabled")
+ << QString::fromAscii("offlineWebApplicationCacheEnabled")
+ << QString::fromAscii("pluginsEnabled")
+ << QString::fromAscii("printElementBackgrounds")
+ << QString::fromAscii("privateBrowsingEnabled")
+ << QString::fromAscii("zoomTextOnly");
+
+ // Merely tests that setting gets stored (in QWebSettings), behavioural tests are in WebKit.
+ for (int b = 0; b <= 1; b++) {
+ bool value = !!b;
+ foreach (const QString& name, settingsList)
+ s->setProperty(name.toAscii().data(), value);
+ for (int i = 0; i < 2; i++) {
+ foreach (const QString& name, settingsList)
+ QCOMPARE(s->property(name.toAscii().data()).toBool(), value);
+ }
+ }
+}
+
+#if QT_VERSION >= 0x040703
+void tst_QDeclarativeWebView::backgroundColor()
+{
+ // We test here the rendering of the background.
+ QDeclarativeEngine engine;
+ QDeclarativeComponent component(&engine, QUrl("qrc:///resources/webviewbackgroundcolor.qml"));
+ checkNoErrors(component);
+ QObject* wv = component.create();
+ QVERIFY(wv);
+ QCOMPARE(wv->property("backgroundColor").value<QColor>(), QColor(Qt::red));
+ QDeclarativeView view;
+ view.setSource(QUrl("qrc:///resources/webviewbackgroundcolor.qml"));
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ QPixmap result(view.width(), view.height());
+ QPainter painter(&result);
+ view.render(&painter);
+ QPixmap reference(view.width(), view.height());
+ reference.fill(Qt::red);
+ QCOMPARE(reference, result);
+
+ // We test the emission of the backgroundColorChanged signal.
+ QSignalSpy spyColorChanged(wv, SIGNAL(backgroundColorChanged()));
+ wv->setProperty("backgroundColor", Qt::red);
+ QCOMPARE(spyColorChanged.count(), 0);
+ wv->setProperty("backgroundColor", Qt::green);
+ QCOMPARE(spyColorChanged.count(), 1);
+}
+#endif
+
+void tst_QDeclarativeWebView::checkNoErrors(const QDeclarativeComponent& component)
+{
+ // Wait until the component is ready
+ QTRY_VERIFY(component.isReady() || component.isError());
+ if (component.isError()) {
+ QList<QDeclarativeError> errors = component.errors();
+ for (int ii = 0; ii < errors.count(); ++ii) {
+ const QDeclarativeError &error = errors.at(ii);
+ QByteArray errorStr = QByteArray::number(error.line()) + ":" +
+ QByteArray::number(error.column()) + ":" +
+ error.description().toUtf8();
+ qWarning() << errorStr;
+ }
+ }
+ QVERIFY(!component.isError());
+}
+
+QTEST_MAIN(tst_QDeclarativeWebView)
+#include "tst_qdeclarativewebview.moc"
+
+QT_END_NAMESPACE
diff --git a/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.qrc b/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.qrc
new file mode 100644
index 0000000..fb66ad8
--- /dev/null
+++ b/Source/WebKit/qt/tests/qdeclarativewebview/tst_qdeclarativewebview.qrc
@@ -0,0 +1,22 @@
+<RCC>
+ <qresource prefix="/">
+ <file>resources/basic.html</file>
+ <file>resources/basic.png</file>
+ <file>resources/basic.qml</file>
+ <file>resources/elements.html</file>
+ <file>resources/elements.qml</file>
+ <file>resources/forward.html</file>
+ <file>resources/forward.png</file>
+ <file>resources/javaScript.html</file>
+ <file>resources/javaScript.qml</file>
+ <file>resources/loadError.qml</file>
+ <file>resources/newwindows.html</file>
+ <file>resources/newwindows.qml</file>
+ <file>resources/propertychanges.qml</file>
+ <file>resources/sample.html</file>
+ <file>resources/sethtml.qml</file>
+ <file>resources/webviewbackgroundcolor.qml</file>
+ <file>resources/webviewtestdefault.qml</file>
+ <file>resources/webviewtest.qml</file>
+ </qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro b/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro
new file mode 100644
index 0000000..e5494ae
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro
@@ -0,0 +1,6 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
+contains(DEFINES, ENABLE_WEBGL=1) {
+ QT += opengl
+}
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/resources/56929.html b/Source/WebKit/qt/tests/qgraphicswebview/resources/56929.html
new file mode 100644
index 0000000..2f7fa97
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/resources/56929.html
@@ -0,0 +1,8 @@
+<body style="background-color: white">
+ <div id="1" style="width: 50%; height: 50%; background-color: green"/>
+ <script>
+ function resizeDiv() {
+ document.getElementById("1").setAttribute("style", "width: 150%; height: 150%; background-color: green");
+ }
+ </script>
+</body>
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/resources/input_types.html b/Source/WebKit/qt/tests/qgraphicswebview/resources/input_types.html
new file mode 100644
index 0000000..18ab314
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/resources/input_types.html
@@ -0,0 +1,8 @@
+<html><body>
+<input type='text' maxlength='20' style='position: absolute; left: 10px; top: 0px; height: 50px; width: 100px;'/><br>
+<input type='password' style='position: absolute; left: 10px; top: 50px; height: 50px; width: 100px;'/><br>
+<input type='tel' style='position: absolute; left: 10px; top: 100px; height: 50px; width: 100px;'/><br>
+<input type='number' style='position: absolute; left: 10px; top: 150px; height: 50px; width: 100px;'/><br>
+<input type='email' style='position: absolute; left: 10px; top: 200px; height: 50px; width: 100px;'/><br>
+<input type='url' style='position: absolute; left: 10px; top: 250px; height: 50px; width: 100px;'/><br>"
+</body></html> \ No newline at end of file
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html b/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html
new file mode 100644
index 0000000..bc592fb
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html
@@ -0,0 +1,45 @@
+<html>
+ <body style="margin: 0">
+ <canvas width="100" height="100"></canvas>
+ </body>
+</html>
+<script>
+ var canvas = document.getElementsByTagName("canvas")[0];
+ gl = canvas.getContext("experimental-webgl");
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, "attribute vec4 vPosition;\nvoid main() { gl_Position = vPosition; }");
+ gl.compileShader(vertexShader);
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+ gl.compileShader(fragmentShader);
+
+ var shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.bindAttribLocation(shaderProgram, 0, "vPosition");
+ gl.linkProgram(shaderProgram);
+
+ gl.useProgram(shaderProgram);
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+ var vertices = [-1.0, -1.0,
+ 0.0, 0.0,
+ -1.0, 1.0];
+ var seedX = -1.0;
+ var seedY = 1.0;
+ vertices
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+ gl.flush();
+</script>
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html b/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html
new file mode 100644
index 0000000..474a56d
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html
@@ -0,0 +1,46 @@
+<html>
+ <body style="margin: 0">
+ <canvas width="100" height="100"></canvas>
+ </body>
+</html>
+<script>
+ var canvas = document.getElementsByTagName("canvas")[0];
+ gl = canvas.getContext("experimental-webgl");
+ gl.clearColor(0.0, 1.0, 0.0, 1.0);
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, "attribute vec4 vPosition;\nvoid main() { gl_Position = vPosition; }");
+ gl.compileShader(vertexShader);
+
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+ gl.compileShader(fragmentShader);
+
+ var shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.bindAttribLocation(shaderProgram, 0, "vPosition");
+ gl.linkProgram(shaderProgram);
+
+ gl.useProgram(shaderProgram);
+
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+ var vertices = [-1.0, -1.0,
+ 0.0, 0.0,
+ 1.0, -1.0];
+ var seedX = -1.0;
+ var seedY = 1.0;
+ vertices
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+ gl.enableVertexAttribArray(0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+ gl.flush();
+ gl.finish();
+</script>
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp b/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp
new file mode 100644
index 0000000..ed162c4
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp
@@ -0,0 +1,602 @@
+/*
+ Copyright (C) 2009 Jakub Wieczorek <faw217@gmail.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "../util.h"
+#include <QtTest/QtTest>
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsView>
+#include <QStyleOptionGraphicsItem>
+#include <qgraphicswebview.h>
+#include <qwebpage.h>
+#include <qwebframe.h>
+
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+#include <QGLWidget>
+#endif
+
+class tst_QGraphicsWebView : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void qgraphicswebview();
+ void crashOnViewlessWebPages();
+ void microFocusCoordinates();
+ void focusInputTypes();
+ void crashOnSetScaleBeforeSetUrl();
+ void widgetsRenderingThroughCache();
+ void setPalette_data();
+ void setPalette();
+ void renderHints();
+#if defined(ENABLE_TILED_BACKING_STORE) && ENABLE_TILED_BACKING_STORE
+ void bug56929();
+#endif
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+ void webglSoftwareFallbackVerticalOrientation();
+ void webglSoftwareFallbackHorizontalOrientation();
+
+private:
+ void compareCanvasToImage(const QUrl&, const QImage&);
+#endif
+};
+
+void tst_QGraphicsWebView::qgraphicswebview()
+{
+ QGraphicsWebView item;
+ item.url();
+ item.title();
+ item.icon();
+ item.zoomFactor();
+ item.history();
+ item.settings();
+ item.page();
+ item.setPage(0);
+ item.page();
+ item.setUrl(QUrl());
+ item.setZoomFactor(0);
+ item.load(QUrl());
+ item.setHtml(QString());
+ item.setContent(QByteArray());
+ item.isModified();
+}
+
+class WebPage : public QWebPage
+{
+ Q_OBJECT
+
+public:
+ WebPage(QObject* parent = 0): QWebPage(parent)
+ {
+ }
+
+ QGraphicsWebView* webView;
+
+private slots:
+ // Force a webview deletion during the load.
+ // It should not cause WebPage to crash due to
+ // it accessing invalid pageClient pointer.
+ void aborting()
+ {
+ delete webView;
+ }
+};
+
+class GraphicsWebView : public QGraphicsWebView
+{
+ Q_OBJECT
+
+public:
+ GraphicsWebView(QGraphicsItem* parent = 0): QGraphicsWebView(parent)
+ {
+ }
+
+ void fireMouseClick(QPointF point) {
+ QGraphicsSceneMouseEvent presEv(QEvent::GraphicsSceneMousePress);
+ presEv.setPos(point);
+ presEv.setButton(Qt::LeftButton);
+ presEv.setButtons(Qt::LeftButton);
+ QGraphicsSceneMouseEvent relEv(QEvent::GraphicsSceneMouseRelease);
+ relEv.setPos(point);
+ relEv.setButton(Qt::LeftButton);
+ relEv.setButtons(Qt::LeftButton);
+ QGraphicsWebView::sceneEvent(&presEv);
+ QGraphicsWebView::sceneEvent(&relEv);
+ }
+};
+
+void tst_QGraphicsWebView::crashOnViewlessWebPages()
+{
+ QGraphicsScene scene;
+ QGraphicsView view(&scene);
+
+ QGraphicsWebView* webView = new QGraphicsWebView;
+ WebPage* page = new WebPage;
+ webView->setPage(page);
+ page->webView = webView;
+ scene.addItem(webView);
+
+ view.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ view.resize(600, 480);
+ webView->resize(view.geometry().size());
+
+ QCoreApplication::processEvents();
+ view.show();
+
+ // Resizing the page will resize and layout the empty "about:blank"
+ // page, so we first connect the signal afterward.
+ connect(page->mainFrame(), SIGNAL(initialLayoutCompleted()), page, SLOT(aborting()));
+
+ page->mainFrame()->load(QUrl("data:text/html,"
+ "<frameset cols=\"25%,75%\">"
+ "<frame src=\"data:text/html,foo \">"
+ "<frame src=\"data:text/html,bar\">"
+ "</frameset>"));
+
+ QVERIFY(waitForSignal(page, SIGNAL(loadFinished(bool))));
+ delete page;
+}
+
+void tst_QGraphicsWebView::crashOnSetScaleBeforeSetUrl()
+{
+ QGraphicsWebView* webView = new QGraphicsWebView;
+ webView->setScale(2.0);
+ delete webView;
+}
+
+void tst_QGraphicsWebView::widgetsRenderingThroughCache()
+{
+ // Widgets should be rendered the same way with and without
+ // intermediate cache (tiling for example).
+ // See bug https://bugs.webkit.org/show_bug.cgi?id=47767 where
+ // widget are rendered as disabled when caching is using.
+
+ QGraphicsWebView* webView = new QGraphicsWebView;
+ webView->setHtml(QLatin1String("<body style=\"background-color: white\"><input type=range></input><input type=checkbox></input><input type=radio></input><input type=file></input></body>"));
+
+ QGraphicsView view;
+ view.show();
+ QGraphicsScene* scene = new QGraphicsScene(&view);
+ view.setScene(scene);
+ scene->addItem(webView);
+ view.setGeometry(QRect(0, 0, 500, 500));
+ QWidget *const widget = &view;
+ QTest::qWaitForWindowShown(widget);
+
+ // 1. Reference without tiling.
+ webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, false);
+ QPixmap referencePixmap(view.size());
+ widget->render(&referencePixmap);
+
+ // 2. With tiling.
+ webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true);
+ QPixmap viewWithTiling(view.size());
+ widget->render(&viewWithTiling);
+ QApplication::processEvents();
+ viewWithTiling.fill();
+ widget->render(&viewWithTiling);
+
+ QCOMPARE(referencePixmap.toImage(), viewWithTiling.toImage());
+}
+
+#if defined(ENABLE_TILED_BACKING_STORE) && ENABLE_TILED_BACKING_STORE
+void tst_QGraphicsWebView::bug56929()
+{
+ // When rendering from tiles sychronous layout should not be triggered
+ // and scrollbars should be in sync with the size of the document in the displayed state.
+
+ QGraphicsWebView* webView = new QGraphicsWebView();
+ webView->setGeometry(QRectF(0.0, 0.0, 100.0, 100.0));
+ QGraphicsView view(new QGraphicsScene());
+ view.scene()->setParent(&view);
+ view.scene()->addItem(webView);
+ webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true);
+ QUrl url("qrc:///resources/56929.html");
+ webView->load(url);
+ QVERIFY(waitForSignal(webView, SIGNAL(loadFinished(bool))));
+ QStyleOptionGraphicsItem option;
+ option.exposedRect = webView->geometry();
+ QImage img(option.exposedRect.width(), option.exposedRect.height(), QImage::Format_ARGB32_Premultiplied);
+ QPainter painter(&img);
+ // This will not paint anything as the tiles are not ready, yet.
+ webView->paint(&painter, &option);
+ QApplication::processEvents();
+ webView->paint(&painter, &option);
+ QCOMPARE(img.pixel(option.exposedRect.width() - 2, option.exposedRect.height() / 2), qRgba(255, 255, 255, 255));
+ painter.fillRect(option.exposedRect, Qt::black);
+ QCOMPARE(img.pixel(option.exposedRect.width() - 2, option.exposedRect.height() / 2), qRgba(0, 0, 0, 255));
+ webView->page()->mainFrame()->evaluateJavaScript(QString("resizeDiv();"));
+ webView->paint(&painter, &option);
+ QCOMPARE(img.pixel(option.exposedRect.width() - 2, option.exposedRect.height() / 2), qRgba(255, 255, 255, 255));
+}
+#endif
+
+void tst_QGraphicsWebView::microFocusCoordinates()
+{
+ QWebPage* page = new QWebPage;
+ QGraphicsWebView* webView = new QGraphicsWebView;
+ webView->setPage( page );
+ QGraphicsView* view = new QGraphicsView;
+ QGraphicsScene* scene = new QGraphicsScene(view);
+ view->setScene(scene);
+ scene->addItem(webView);
+ view->setGeometry(QRect(0,0,500,500));
+
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input1' style='font--family: serif' value='' maxlength='20'/><br>" \
+ "<canvas id='canvas1' width='500' height='500'></canvas>" \
+ "<input type='password'/><br>" \
+ "<canvas id='canvas2' width='500' height='500'></canvas>" \
+ "</body></html>");
+
+ page->mainFrame()->setFocus();
+
+ QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus);
+ QVERIFY(initialMicroFocus.isValid());
+
+ page->mainFrame()->scroll(0,300);
+
+ QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus);
+ QVERIFY(currentMicroFocus.isValid());
+
+ QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-300)), currentMicroFocus.toRect());
+
+ delete view;
+}
+
+void tst_QGraphicsWebView::focusInputTypes()
+{
+ QWebPage* page = new QWebPage;
+ GraphicsWebView* webView = new GraphicsWebView;
+ webView->setPage( page );
+ QGraphicsView* view = new QGraphicsView;
+ QGraphicsScene* scene = new QGraphicsScene(view);
+ view->setScene(scene);
+ scene->addItem(webView);
+ view->setGeometry(QRect(0,0,500,500));
+ QCoreApplication::processEvents();
+ QUrl url("qrc:///resources/input_types.html");
+ page->mainFrame()->load(url);
+ page->mainFrame()->setFocus();
+
+ QVERIFY(waitForSignal(page, SIGNAL(loadFinished(bool))));
+
+ // 'text' type
+ webView->fireMouseClick(QPointF(20.0, 10.0));
+#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN)
+ QVERIFY(webView->inputMethodHints() & Qt::ImhNoAutoUppercase);
+ QVERIFY(webView->inputMethodHints() & Qt::ImhNoPredictiveText);
+#else
+ QVERIFY(webView->inputMethodHints() == Qt::ImhNone);
+#endif
+
+ // 'password' field
+ webView->fireMouseClick(QPointF(20.0, 60.0));
+ QVERIFY(webView->inputMethodHints() & Qt::ImhHiddenText);
+
+ // 'tel' field
+ webView->fireMouseClick(QPointF(20.0, 110.0));
+ QVERIFY(webView->inputMethodHints() & Qt::ImhDialableCharactersOnly);
+
+ // 'number' field
+ webView->fireMouseClick(QPointF(20.0, 160.0));
+ QVERIFY(webView->inputMethodHints() & Qt::ImhDigitsOnly);
+
+ // 'email' field
+ webView->fireMouseClick(QPointF(20.0, 210.0));
+ QVERIFY(webView->inputMethodHints() & Qt::ImhEmailCharactersOnly);
+
+ // 'url' field
+ webView->fireMouseClick(QPointF(20.0, 260.0));
+ QVERIFY(webView->inputMethodHints() & Qt::ImhUrlCharactersOnly);
+
+ delete webView;
+ delete view;
+}
+
+void tst_QGraphicsWebView::setPalette_data()
+{
+ QTest::addColumn<bool>("active");
+ QTest::addColumn<bool>("background");
+ QTest::newRow("activeBG") << true << true;
+ QTest::newRow("activeFG") << true << false;
+ QTest::newRow("inactiveBG") << false << true;
+ QTest::newRow("inactiveFG") << false << false;
+}
+
+// Render a QGraphicsWebView to a QImage twice, each time with a different palette set,
+// verify that images rendered are not the same, confirming WebCore usage of
+// custom palette on selections.
+void tst_QGraphicsWebView::setPalette()
+{
+ QString html = "<html><head></head>"
+ "<body>"
+ "Some text here"
+ "</body>"
+ "</html>";
+
+ QFETCH(bool, active);
+ QFETCH(bool, background);
+
+ QWidget* activeView = 0;
+
+ // Use controlView to manage active/inactive state of test views by raising
+ // or lowering their position in the window stack.
+ QGraphicsScene controlScene;
+ QGraphicsView controlView(&controlScene);
+ QGraphicsWebView controlWebView;
+ controlScene.addItem(&controlWebView);
+ controlWebView.setHtml(html);
+ controlWebView.setGeometry(QRectF(0, 0, 200, 200));
+
+ QGraphicsScene scene1;
+ QGraphicsView view1(&scene1);
+ view1.setSceneRect(0, 0, 300, 300);
+ QGraphicsWebView webView1;
+ webView1.setResizesToContents(true);
+ scene1.addItem(&webView1);
+ webView1.setFocus();
+
+ QPalette palette1;
+ QBrush brush1(Qt::red);
+ brush1.setStyle(Qt::SolidPattern);
+ if (active && background) {
+ // Rendered image must have red background on an active QGraphicsWebView.
+ palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1);
+ } else if (active && !background) {
+ // Rendered image must have red foreground on an active QGraphicsWebView.
+ palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1);
+ } else if (!active && background) {
+ // Rendered image must have red background on an inactive QGraphicsWebView.
+ palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1);
+ } else if (!active && !background) {
+ // Rendered image must have red foreground on an inactive QGraphicsWebView.
+ palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1);
+ }
+
+ webView1.setHtml(html);
+ view1.resize(webView1.page()->viewportSize());
+ webView1.setPalette(palette1);
+ view1.show();
+
+ QVERIFY(webView1.palette() == palette1);
+ QVERIFY(webView1.page()->palette() == palette1);
+
+ QTest::qWaitForWindowShown(&view1);
+
+ if (!active) {
+ controlView.show();
+ QTest::qWaitForWindowShown(&controlView);
+ activeView = &controlView;
+ controlView.activateWindow();
+ } else {
+ view1.activateWindow();
+ activeView = &view1;
+ }
+
+ QTRY_COMPARE(QApplication::activeWindow(), activeView);
+
+ webView1.page()->triggerAction(QWebPage::SelectAll);
+
+ QImage img1(webView1.page()->viewportSize(), QImage::Format_ARGB32);
+ QPainter painter1(&img1);
+ webView1.page()->currentFrame()->render(&painter1);
+ painter1.end();
+ view1.close();
+ controlView.close();
+
+ QGraphicsScene scene2;
+ QGraphicsView view2(&scene2);
+ view2.setSceneRect(0, 0, 300, 300);
+ QGraphicsWebView webView2;
+ webView2.setResizesToContents(true);
+ scene2.addItem(&webView2);
+ webView2.setFocus();
+
+ QPalette palette2;
+ QBrush brush2(Qt::blue);
+ brush2.setStyle(Qt::SolidPattern);
+ if (active && background) {
+ // Rendered image must have blue background on an active QGraphicsWebView.
+ palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2);
+ } else if (active && !background) {
+ // Rendered image must have blue foreground on an active QGraphicsWebView.
+ palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2);
+ } else if (!active && background) {
+ // Rendered image must have blue background on an inactive QGraphicsWebView.
+ palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2);
+ } else if (!active && !background) {
+ // Rendered image must have blue foreground on an inactive QGraphicsWebView.
+ palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2);
+ }
+
+ webView2.setHtml(html);
+ view2.resize(webView2.page()->viewportSize());
+ webView2.setPalette(palette2);
+ view2.show();
+
+ QTest::qWaitForWindowShown(&view2);
+
+ if (!active) {
+ controlView.show();
+ QTest::qWaitForWindowShown(&controlView);
+ activeView = &controlView;
+ controlView.activateWindow();
+ } else {
+ view2.activateWindow();
+ activeView = &view2;
+ }
+
+ QTRY_COMPARE(QApplication::activeWindow(), activeView);
+
+ webView2.page()->triggerAction(QWebPage::SelectAll);
+
+ QImage img2(webView2.page()->viewportSize(), QImage::Format_ARGB32);
+ QPainter painter2(&img2);
+ webView2.page()->currentFrame()->render(&painter2);
+ painter2.end();
+
+ view2.close();
+ controlView.close();
+
+ QVERIFY(img1 != img2);
+}
+
+void tst_QGraphicsWebView::renderHints()
+{
+ QGraphicsWebView webView;
+
+ // default is only text antialiasing + smooth pixmap transform
+ QVERIFY(!(webView.renderHints() & QPainter::Antialiasing));
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::Antialiasing, true);
+ QVERIFY(webView.renderHints() & QPainter::Antialiasing);
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::Antialiasing, false);
+ QVERIFY(!(webView.renderHints() & QPainter::Antialiasing));
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ QVERIFY(!(webView.renderHints() & QPainter::Antialiasing));
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::SmoothPixmapTransform, false);
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform));
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+}
+
+class GraphicsView : public QGraphicsView {
+public:
+ GraphicsView();
+ QGraphicsWebView* m_webView;
+};
+
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+bool compareImagesFuzzyPixelCount(const QImage& image1, const QImage& image2, qreal tolerance = 0.05)
+{
+ if (image1.size() != image2.size())
+ return false;
+
+ unsigned diffPixelCount = 0;
+ for (int row = 0; row < image1.size().width(); ++row) {
+ for (int column = 0; column < image1.size().height(); ++column)
+ if (image1.pixel(row, column) != image2.pixel(row, column))
+ ++diffPixelCount;
+ }
+
+ if (diffPixelCount > (image1.size().width() * image1.size().height()) * tolerance)
+ return false;
+
+ return true;
+}
+
+GraphicsView::GraphicsView()
+{
+ QGraphicsScene* const scene = new QGraphicsScene(this);
+ setScene(scene);
+
+ m_webView = new QGraphicsWebView;
+ scene->addItem(m_webView);
+
+ m_webView->page()->settings()->setAttribute(QWebSettings::WebGLEnabled, true);
+ m_webView->setResizesToContents(true);
+
+ setFrameShape(QFrame::NoFrame);
+ setViewport(new QGLWidget);
+}
+
+void tst_QGraphicsWebView::webglSoftwareFallbackVerticalOrientation()
+{
+ QSize canvasSize(100, 100);
+ QImage reference(canvasSize, QImage::Format_ARGB32);
+ reference.fill(0xFF00FF00);
+ { // Reference.
+ QPainter painter(&reference);
+ QPolygonF triangleUp;
+ triangleUp << QPointF(0, canvasSize.height())
+ << QPointF(canvasSize.width(), canvasSize.height())
+ << QPointF(canvasSize.width() / 2.0, canvasSize.height() / 2.0);
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(Qt::red);
+ painter.drawPolygon(triangleUp);
+ }
+
+ compareCanvasToImage(QUrl(QLatin1String("qrc:///resources/pointing_up.html")), reference);
+}
+
+void tst_QGraphicsWebView::webglSoftwareFallbackHorizontalOrientation()
+{
+ QSize canvasSize(100, 100);
+ QImage reference(canvasSize, QImage::Format_ARGB32);
+ reference.fill(0xFF00FF00);
+ { // Reference.
+ QPainter painter(&reference);
+ QPolygonF triangleUp;
+ triangleUp << QPointF(0, 0)
+ << QPointF(0, canvasSize.height())
+ << QPointF(canvasSize.width() / 2.0, canvasSize.height() / 2.0);
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(Qt::red);
+ painter.drawPolygon(triangleUp);
+ }
+
+ compareCanvasToImage(QUrl(QLatin1String("qrc:///resources/pointing_right.html")), reference);
+}
+
+void tst_QGraphicsWebView::compareCanvasToImage(const QUrl& url, const QImage& reference)
+{
+ GraphicsView view;
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+
+ QGraphicsWebView* const graphicsWebView = view.m_webView;
+ graphicsWebView->load(url);
+ QVERIFY(waitForSignal(graphicsWebView, SIGNAL(loadFinished(bool))));
+ { // Force a render, to create the accelerated compositing tree.
+ QPixmap pixmap(view.size());
+ QPainter painter(&pixmap);
+ view.render(&painter);
+ }
+ QApplication::syncX();
+
+ const QSize imageSize = reference.size();
+
+ QImage target(imageSize, QImage::Format_ARGB32);
+ { // Web page content.
+ QPainter painter(&target);
+ QRectF renderRect(0, 0, imageSize.width(), imageSize.height());
+ view.scene()->render(&painter, renderRect, renderRect);
+ }
+ QVERIFY(compareImagesFuzzyPixelCount(target, reference, 0.01));
+}
+#endif
+
+QTEST_MAIN(tst_QGraphicsWebView)
+
+#include "tst_qgraphicswebview.moc"
diff --git a/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc b/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc
new file mode 100644
index 0000000..f929fe7
--- /dev/null
+++ b/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>resources/input_types.html</file>
+ <file>resources/pointing_right.html</file>
+ <file>resources/pointing_up.html</file>
+ <file>resources/56929.html</file>
+ </qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/qwebelement/qwebelement.pro b/Source/WebKit/qt/tests/qwebelement/qwebelement.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebelement/qwebelement.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebelement/resources/image.png b/Source/WebKit/qt/tests/qwebelement/resources/image.png
new file mode 100644
index 0000000..8d70364
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebelement/resources/image.png
Binary files differ
diff --git a/Source/WebKit/qt/tests/qwebelement/resources/style.css b/Source/WebKit/qt/tests/qwebelement/resources/style.css
new file mode 100644
index 0000000..2713dfd
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebelement/resources/style.css
@@ -0,0 +1 @@
+#idP {color: black !important}
diff --git a/Source/WebKit/qt/tests/qwebelement/resources/style2.css b/Source/WebKit/qt/tests/qwebelement/resources/style2.css
new file mode 100644
index 0000000..6575dcb
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebelement/resources/style2.css
@@ -0,0 +1 @@
+#idP {color: green ! important}
diff --git a/Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp b/Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp
new file mode 100644
index 0000000..9e9948a
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp
@@ -0,0 +1,1043 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <QtTest/QtTest>
+#include <qwebpage.h>
+#include <qwidget.h>
+#include <qwebview.h>
+#include <qwebframe.h>
+#include <qwebelement.h>
+#include <util.h>
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QWebElement : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebElement();
+ virtual ~tst_QWebElement();
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void textHtml();
+ void simpleCollection();
+ void attributes();
+ void attributesNS();
+ void listAttributes();
+ void classes();
+ void namespaceURI();
+ void iteration();
+ void nonConstIterator();
+ void constIterator();
+ void foreachManipulation();
+ void emptyCollection();
+ void appendCollection();
+ void evaluateJavaScript();
+ void documentElement();
+ void frame();
+ void style();
+ void computedStyle();
+ void appendAndPrepend();
+ void insertBeforeAndAfter();
+ void remove();
+ void clear();
+ void replaceWith();
+ void encloseWith();
+ void encloseContentsWith();
+ void nullSelect();
+ void firstChildNextSibling();
+ void lastChildPreviousSibling();
+ void hasSetFocus();
+ void render();
+ void addElementToHead();
+
+private:
+ QWebView* m_view;
+ QWebPage* m_page;
+ QWebFrame* m_mainFrame;
+};
+
+tst_QWebElement::tst_QWebElement()
+{
+}
+
+tst_QWebElement::~tst_QWebElement()
+{
+}
+
+void tst_QWebElement::init()
+{
+ m_view = new QWebView();
+ m_page = m_view->page();
+ m_mainFrame = m_page->mainFrame();
+}
+
+void tst_QWebElement::cleanup()
+{
+ delete m_view;
+}
+
+void tst_QWebElement::textHtml()
+{
+ QString html = "<head></head><body><p>test</p></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+ QVERIFY(!body.isNull());
+
+ QCOMPARE(body.toPlainText(), QString("test"));
+ QCOMPARE(body.toPlainText(), m_mainFrame->toPlainText());
+
+ QCOMPARE(body.toInnerXml(), html);
+}
+
+void tst_QWebElement::simpleCollection()
+{
+ QString html = "<body><p>first para</p><p>second para</p></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+
+ QWebElementCollection list = body.findAll("p");
+ QCOMPARE(list.count(), 2);
+ QCOMPARE(list.at(0).toPlainText(), QString("first para"));
+ QCOMPARE(list.at(1).toPlainText(), QString("second para"));
+}
+
+void tst_QWebElement::attributes()
+{
+ m_mainFrame->setHtml("<body><p>Test");
+ QWebElement body = m_mainFrame->documentElement();
+
+ QVERIFY(!body.hasAttribute("title"));
+ QVERIFY(!body.hasAttributes());
+
+ body.setAttribute("title", "test title");
+
+ QVERIFY(body.hasAttributes());
+ QVERIFY(body.hasAttribute("title"));
+
+ QCOMPARE(body.attribute("title"), QString("test title"));
+
+ body.removeAttribute("title");
+
+ QVERIFY(!body.hasAttribute("title"));
+ QVERIFY(!body.hasAttributes());
+
+ QCOMPARE(body.attribute("does-not-exist", "testvalue"), QString("testvalue"));
+}
+
+void tst_QWebElement::attributesNS()
+{
+ QString content = "<html xmlns=\"http://www.w3.org/1999/xhtml\" "
+ "xmlns:svg=\"http://www.w3.org/2000/svg\">"
+ "<body><svg:svg id=\"foobar\" width=\"400px\" height=\"300px\">"
+ "</svg:svg></body></html>";
+
+ m_mainFrame->setContent(content.toUtf8(), "application/xhtml+xml");
+
+ QWebElement svg = m_mainFrame->findFirstElement("svg");
+ QVERIFY(!svg.isNull());
+
+ QVERIFY(!svg.hasAttributeNS("http://www.w3.org/2000/svg", "foobar"));
+ QCOMPARE(svg.attributeNS("http://www.w3.org/2000/svg", "foobar", "defaultblah"), QString("defaultblah"));
+ svg.setAttributeNS("http://www.w3.org/2000/svg", "svg:foobar", "true");
+ QVERIFY(svg.hasAttributeNS("http://www.w3.org/2000/svg", "foobar"));
+ QCOMPARE(svg.attributeNS("http://www.w3.org/2000/svg", "foobar", "defaultblah"), QString("true"));
+}
+
+void tst_QWebElement::listAttributes()
+{
+ QString content = "<html xmlns=\"http://www.w3.org/1999/xhtml\" "
+ "xmlns:svg=\"http://www.w3.org/2000/svg\">"
+ "<body><svg:svg foo=\"\" svg:bar=\"\">"
+ "</svg:svg></body></html>";
+
+ m_mainFrame->setContent(content.toUtf8(), "application/xhtml+xml");
+
+ QWebElement svg = m_mainFrame->findFirstElement("svg");
+ QVERIFY(!svg.isNull());
+
+ QVERIFY(svg.attributeNames().contains("foo"));
+ QVERIFY(svg.attributeNames("http://www.w3.org/2000/svg").contains("bar"));
+
+ svg.setAttributeNS("http://www.w3.org/2000/svg", "svg:foobar", "true");
+ QVERIFY(svg.attributeNames().contains("foo"));
+ QStringList attributes = svg.attributeNames("http://www.w3.org/2000/svg");
+ QCOMPARE(attributes.size(), 2);
+ QVERIFY(attributes.contains("bar"));
+ QVERIFY(attributes.contains("foobar"));
+}
+
+void tst_QWebElement::classes()
+{
+ m_mainFrame->setHtml("<body><p class=\"a b c d a c\">Test");
+
+ QWebElement body = m_mainFrame->documentElement();
+ QCOMPARE(body.classes().count(), 0);
+
+ QWebElement p = m_mainFrame->documentElement().findAll("p").at(0);
+ QStringList classes = p.classes();
+ QCOMPARE(classes.count(), 4);
+ QCOMPARE(classes[0], QLatin1String("a"));
+ QCOMPARE(classes[1], QLatin1String("b"));
+ QCOMPARE(classes[2], QLatin1String("c"));
+ QCOMPARE(classes[3], QLatin1String("d"));
+ QVERIFY(p.hasClass("a"));
+ QVERIFY(p.hasClass("b"));
+ QVERIFY(p.hasClass("c"));
+ QVERIFY(p.hasClass("d"));
+ QVERIFY(!p.hasClass("e"));
+
+ p.addClass("f");
+ QVERIFY(p.hasClass("f"));
+ p.addClass("a");
+ QCOMPARE(p.classes().count(), 5);
+ QVERIFY(p.hasClass("a"));
+ QVERIFY(p.hasClass("b"));
+ QVERIFY(p.hasClass("c"));
+ QVERIFY(p.hasClass("d"));
+
+ p.toggleClass("a");
+ QVERIFY(!p.hasClass("a"));
+ QVERIFY(p.hasClass("b"));
+ QVERIFY(p.hasClass("c"));
+ QVERIFY(p.hasClass("d"));
+ QVERIFY(p.hasClass("f"));
+ QCOMPARE(p.classes().count(), 4);
+ p.toggleClass("f");
+ QVERIFY(!p.hasClass("f"));
+ QCOMPARE(p.classes().count(), 3);
+ p.toggleClass("a");
+ p.toggleClass("f");
+ QVERIFY(p.hasClass("a"));
+ QVERIFY(p.hasClass("f"));
+ QCOMPARE(p.classes().count(), 5);
+
+ p.removeClass("f");
+ QVERIFY(!p.hasClass("f"));
+ QCOMPARE(p.classes().count(), 4);
+ p.removeClass("d");
+ QVERIFY(!p.hasClass("d"));
+ QCOMPARE(p.classes().count(), 3);
+ p.removeClass("not-exist");
+ QCOMPARE(p.classes().count(), 3);
+ p.removeClass("c");
+ QVERIFY(!p.hasClass("c"));
+ QCOMPARE(p.classes().count(), 2);
+ p.removeClass("b");
+ QVERIFY(!p.hasClass("b"));
+ QCOMPARE(p.classes().count(), 1);
+ p.removeClass("a");
+ QVERIFY(!p.hasClass("a"));
+ QCOMPARE(p.classes().count(), 0);
+ p.removeClass("foobar");
+ QCOMPARE(p.classes().count(), 0);
+}
+
+void tst_QWebElement::namespaceURI()
+{
+ QString content = "<html xmlns=\"http://www.w3.org/1999/xhtml\" "
+ "xmlns:svg=\"http://www.w3.org/2000/svg\">"
+ "<body><svg:svg id=\"foobar\" width=\"400px\" height=\"300px\">"
+ "</svg:svg></body></html>";
+
+ m_mainFrame->setContent(content.toUtf8(), "application/xhtml+xml");
+ QWebElement body = m_mainFrame->documentElement();
+ QCOMPARE(body.namespaceUri(), QLatin1String("http://www.w3.org/1999/xhtml"));
+
+ QWebElement svg = body.findAll("*#foobar").at(0);
+ QCOMPARE(svg.prefix(), QLatin1String("svg"));
+ QCOMPARE(svg.localName(), QLatin1String("svg"));
+ QCOMPARE(svg.tagName(), QLatin1String("svg:svg"));
+ QCOMPARE(svg.namespaceUri(), QLatin1String("http://www.w3.org/2000/svg"));
+
+}
+
+void tst_QWebElement::iteration()
+{
+ QString html = "<body><p>first para</p><p>second para</p></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+
+ QWebElementCollection paras = body.findAll("p");
+ QList<QWebElement> referenceList = paras.toList();
+
+ QList<QWebElement> foreachList;
+ foreach(QWebElement p, paras) {
+ foreachList.append(p);
+ }
+ QVERIFY(foreachList.count() == 2);
+ QCOMPARE(foreachList.count(), referenceList.count());
+ QCOMPARE(foreachList.at(0), referenceList.at(0));
+ QCOMPARE(foreachList.at(1), referenceList.at(1));
+
+ QList<QWebElement> forLoopList;
+ for (int i = 0; i < paras.count(); ++i) {
+ forLoopList.append(paras.at(i));
+ }
+ QVERIFY(foreachList.count() == 2);
+ QCOMPARE(foreachList.count(), referenceList.count());
+ QCOMPARE(foreachList.at(0), referenceList.at(0));
+ QCOMPARE(foreachList.at(1), referenceList.at(1));
+
+ for (int i = 0; i < paras.count(); ++i) {
+ QCOMPARE(paras.at(i), paras[i]);
+ }
+
+ QCOMPARE(paras.at(0), paras.first());
+ QCOMPARE(paras.at(1), paras.last());
+}
+
+void tst_QWebElement::nonConstIterator()
+{
+ QString html = "<body><p>first para</p><p>second para</p></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+ QWebElementCollection paras = body.findAll("p");
+
+ QWebElementCollection::iterator it = paras.begin();
+ QCOMPARE(*it, paras.at(0));
+ ++it;
+ (*it).encloseWith("<div>");
+ QCOMPARE(*it, paras.at(1));
+ ++it;
+ QCOMPARE(it, paras.end());
+}
+
+void tst_QWebElement::constIterator()
+{
+ QString html = "<body><p>first para</p><p>second para</p></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+ const QWebElementCollection paras = body.findAll("p");
+
+ QWebElementCollection::const_iterator it = paras.begin();
+ QCOMPARE(*it, paras.at(0));
+ ++it;
+ QCOMPARE(*it, paras.at(1));
+ ++it;
+ QCOMPARE(it, paras.end());
+}
+
+void tst_QWebElement::foreachManipulation()
+{
+ QString html = "<body><p>first para</p><p>second para</p></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+
+ foreach(QWebElement p, body.findAll("p")) {
+ p.setInnerXml("<div>foo</div><div>bar</div>");
+ }
+
+ QCOMPARE(body.findAll("div").count(), 4);
+}
+
+void tst_QWebElement::emptyCollection()
+{
+ QWebElementCollection emptyCollection;
+ QCOMPARE(emptyCollection.count(), 0);
+}
+
+void tst_QWebElement::appendCollection()
+{
+ QString html = "<body><span class='a'>aaa</span><p>first para</p><div>foo</div>"
+ "<span class='b'>bbb</span><p>second para</p><div>bar</div></body>";
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement();
+
+ QWebElementCollection collection = body.findAll("p");
+ QCOMPARE(collection.count(), 2);
+
+ collection.append(body.findAll("div"));
+ QCOMPARE(collection.count(), 4);
+
+ collection += body.findAll("span.a");
+ QCOMPARE(collection.count(), 5);
+
+ QWebElementCollection all = collection + body.findAll("span.b");
+ QCOMPARE(all.count(), 6);
+ QCOMPARE(collection.count(), 5);
+
+ all += collection;
+ QCOMPARE(all.count(), 11);
+
+ QCOMPARE(collection.count(), 5);
+ QWebElementCollection test;
+ test.append(collection);
+ QCOMPARE(test.count(), 5);
+ test.append(QWebElementCollection());
+ QCOMPARE(test.count(), 5);
+}
+
+void tst_QWebElement::evaluateJavaScript()
+{
+ QVariant result;
+ m_mainFrame->setHtml("<body><p>test");
+ QWebElement para = m_mainFrame->findFirstElement("p");
+
+ result = para.evaluateJavaScript("this.tagName");
+ QVERIFY(result.isValid());
+ QVERIFY(result.type() == QVariant::String);
+ QCOMPARE(result.toString(), QLatin1String("P"));
+
+ result = para.evaluateJavaScript("this.hasAttributes()");
+ QVERIFY(result.isValid());
+ QVERIFY(result.type() == QVariant::Bool);
+ QVERIFY(!result.toBool());
+
+ para.evaluateJavaScript("this.setAttribute('align', 'left');");
+ QCOMPARE(para.attribute("align"), QLatin1String("left"));
+
+ result = para.evaluateJavaScript("this.hasAttributes()");
+ QVERIFY(result.isValid());
+ QVERIFY(result.type() == QVariant::Bool);
+ QVERIFY(result.toBool());
+}
+
+void tst_QWebElement::documentElement()
+{
+ m_mainFrame->setHtml("<body><p>Test");
+
+ QWebElement para = m_mainFrame->documentElement().findAll("p").at(0);
+ QVERIFY(para.parent().parent() == m_mainFrame->documentElement());
+ QVERIFY(para.document() == m_mainFrame->documentElement());
+}
+
+void tst_QWebElement::frame()
+{
+ m_mainFrame->setHtml("<body><p>test");
+
+ QWebElement doc = m_mainFrame->documentElement();
+ QVERIFY(doc.webFrame() == m_mainFrame);
+
+ m_mainFrame->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
+ "<p>frame1\">"
+ "<frame src=\"data:text/html,<p>frame2\"></frameset>"));
+
+ waitForSignal(m_page, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(m_mainFrame->childFrames().count(), 2);
+
+ QWebFrame* firstFrame = m_mainFrame->childFrames().at(0);
+ QWebFrame* secondFrame = m_mainFrame->childFrames().at(1);
+
+ QCOMPARE(firstFrame->toPlainText(), QString("frame1"));
+ QCOMPARE(secondFrame->toPlainText(), QString("frame2"));
+
+ QWebElement firstPara = firstFrame->documentElement().findAll("p").at(0);
+ QWebElement secondPara = secondFrame->documentElement().findAll("p").at(0);
+
+ QVERIFY(firstPara.webFrame() == firstFrame);
+ QVERIFY(secondPara.webFrame() == secondFrame);
+}
+
+void tst_QWebElement::style()
+{
+ QString html = "<head>"
+ "<style type='text/css'>"
+ "p { color: green !important }"
+ "#idP { color: red }"
+ ".classP { color : yellow ! important }"
+ "</style>"
+ "</head>"
+ "<body>"
+ "<p id='idP' class='classP' style='color: blue;'>some text</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+
+ QWebElement p = m_mainFrame->documentElement().findAll("p").at(0);
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("blue"));
+ QVERIFY(p.styleProperty("cursor", QWebElement::InlineStyle).isEmpty());
+
+ p.setStyleProperty("color", "red");
+ p.setStyleProperty("cursor", "auto");
+
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("red"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("yellow"));
+ QCOMPARE(p.styleProperty("cursor", QWebElement::InlineStyle), QLatin1String("auto"));
+
+ p.setStyleProperty("color", "green !important");
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("green"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("green"));
+
+ p.setStyleProperty("color", "blue");
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("blue"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("green"));
+
+ p.setStyleProperty("color", "blue !important");
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("blue"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("blue"));
+
+ QString html2 = "<head>"
+ "<style type='text/css'>"
+ "p { color: green }"
+ "#idP { color: red }"
+ ".classP { color: yellow }"
+ "</style>"
+ "</head>"
+ "<body>"
+ "<p id='idP' class='classP' style='color: blue;'>some text</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html2);
+ p = m_mainFrame->documentElement().findAll("p").at(0);
+
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("blue"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("blue"));
+
+ QString html3 = "<head>"
+ "<style type='text/css'>"
+ "p { color: green !important }"
+ "#idP { color: red !important}"
+ ".classP { color: yellow !important}"
+ "</style>"
+ "</head>"
+ "<body>"
+ "<p id='idP' class='classP' style='color: blue !important;'>some text</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html3);
+ p = m_mainFrame->documentElement().findAll("p").at(0);
+
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("blue"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("blue"));
+
+ QString html5 = "<head>"
+ "<style type='text/css'>"
+ "p { color: green }"
+ "#idP { color: red }"
+ ".classP { color: yellow }"
+ "</style>"
+ "</head>"
+ "<body>"
+ "<p id='idP' class='classP'>some text</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html5);
+ p = m_mainFrame->documentElement().findAll("p").at(0);
+
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String(""));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("red"));
+
+ QString html6 = "<head>"
+ "<link rel='stylesheet' href='qrc:/style.css' type='text/css' />"
+ "<style type='text/css'>"
+ "p { color: green }"
+ "#idP { color: red }"
+ ".classP { color: yellow ! important}"
+ "</style>"
+ "</head>"
+ "<body>"
+ "<p id='idP' class='classP' style='color: blue;'>some text</p>"
+ "</body>";
+
+ // in few seconds, the CSS should be completey loaded
+ m_mainFrame->setHtml(html6);
+ waitForSignal(m_page, SIGNAL(loadFinished(bool)), 200);
+
+ p = m_mainFrame->documentElement().findAll("p").at(0);
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("blue"));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("black"));
+
+ QString html7 = "<head>"
+ "<style type='text/css'>"
+ "@import url(qrc:/style2.css);"
+ "</style>"
+ "<link rel='stylesheet' href='qrc:/style.css' type='text/css' />"
+ "</head>"
+ "<body>"
+ "<p id='idP' style='color: blue;'>some text</p>"
+ "</body>";
+
+ // in few seconds, the style should be completey loaded
+ m_mainFrame->setHtml(html7);
+ waitForSignal(m_page, SIGNAL(loadFinished(bool)), 200);
+
+ p = m_mainFrame->documentElement().findAll("p").at(0);
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("black"));
+
+ QString html8 = "<body><p>some text</p></body>";
+
+ m_mainFrame->setHtml(html8);
+ p = m_mainFrame->documentElement().findAll("p").at(0);
+
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String(""));
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String(""));
+}
+
+void tst_QWebElement::computedStyle()
+{
+ QString html = "<body><p>some text</p></body>";
+ m_mainFrame->setHtml(html);
+
+ QWebElement p = m_mainFrame->documentElement().findAll("p").at(0);
+ QCOMPARE(p.styleProperty("cursor", QWebElement::ComputedStyle), QLatin1String("auto"));
+ QVERIFY(!p.styleProperty("cursor", QWebElement::ComputedStyle).isEmpty());
+ QVERIFY(p.styleProperty("cursor", QWebElement::InlineStyle).isEmpty());
+
+ p.setStyleProperty("cursor", "text");
+ p.setStyleProperty("color", "red");
+
+ QCOMPARE(p.styleProperty("cursor", QWebElement::ComputedStyle), QLatin1String("text"));
+ QCOMPARE(p.styleProperty("color", QWebElement::ComputedStyle), QLatin1String("rgb(255, 0, 0)"));
+ QCOMPARE(p.styleProperty("color", QWebElement::InlineStyle), QLatin1String("red"));
+}
+
+void tst_QWebElement::appendAndPrepend()
+{
+ QString html = "<body>"
+ "<p>"
+ "foo"
+ "</p>"
+ "<p>"
+ "bar"
+ "</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+
+ QCOMPARE(body.findAll("p").count(), 2);
+ body.appendInside(body.findFirst("p"));
+ QCOMPARE(body.findAll("p").count(), 2);
+ QCOMPARE(body.findFirst("p").toPlainText(), QString("bar"));
+ QCOMPARE(body.findAll("p").last().toPlainText(), QString("foo"));
+
+ body.appendInside(body.findFirst("p").clone());
+ QCOMPARE(body.findAll("p").count(), 3);
+ QCOMPARE(body.findFirst("p").toPlainText(), QString("bar"));
+ QCOMPARE(body.findAll("p").last().toPlainText(), QString("bar"));
+
+ body.prependInside(body.findAll("p").at(1).clone());
+ QCOMPARE(body.findAll("p").count(), 4);
+ QCOMPARE(body.findFirst("p").toPlainText(), QString("foo"));
+
+ body.findFirst("p").appendInside("<div>booyakasha</div>");
+ QCOMPARE(body.findAll("p div").count(), 1);
+ QCOMPARE(body.findFirst("p div").toPlainText(), QString("booyakasha"));
+
+ body.findFirst("div").prependInside("<code>yepp</code>");
+ QCOMPARE(body.findAll("p div code").count(), 1);
+ QCOMPARE(body.findFirst("p div code").toPlainText(), QString("yepp"));
+}
+
+void tst_QWebElement::insertBeforeAndAfter()
+{
+ QString html = "<body>"
+ "<p>"
+ "foo"
+ "</p>"
+ "<div>"
+ "yeah"
+ "</div>"
+ "<p>"
+ "bar"
+ "</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+ QWebElement div = body.findFirst("div");
+
+ QCOMPARE(body.findAll("p").count(), 2);
+ QCOMPARE(body.findAll("div").count(), 1);
+
+ div.prependOutside(body.findAll("p").last().clone());
+ QCOMPARE(body.findAll("p").count(), 3);
+ QCOMPARE(body.findAll("p").at(0).toPlainText(), QString("foo"));
+ QCOMPARE(body.findAll("p").at(1).toPlainText(), QString("bar"));
+ QCOMPARE(body.findAll("p").at(2).toPlainText(), QString("bar"));
+
+ div.appendOutside(body.findFirst("p").clone());
+ QCOMPARE(body.findAll("p").count(), 4);
+ QCOMPARE(body.findAll("p").at(0).toPlainText(), QString("foo"));
+ QCOMPARE(body.findAll("p").at(1).toPlainText(), QString("bar"));
+ QCOMPARE(body.findAll("p").at(2).toPlainText(), QString("foo"));
+ QCOMPARE(body.findAll("p").at(3).toPlainText(), QString("bar"));
+
+ div.prependOutside("<span>hey</span>");
+ QCOMPARE(body.findAll("span").count(), 1);
+
+ div.appendOutside("<span>there</span>");
+ QCOMPARE(body.findAll("span").count(), 2);
+ QCOMPARE(body.findAll("span").at(0).toPlainText(), QString("hey"));
+ QCOMPARE(body.findAll("span").at(1).toPlainText(), QString("there"));
+}
+
+void tst_QWebElement::remove()
+{
+ QString html = "<body>"
+ "<p>"
+ "foo"
+ "</p>"
+ "<div>"
+ "<p>yeah</p>"
+ "</div>"
+ "<p>"
+ "bar"
+ "</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+
+ QCOMPARE(body.findAll("div").count(), 1);
+ QCOMPARE(body.findAll("p").count(), 3);
+
+ QWebElement div = body.findFirst("div");
+ div.takeFromDocument();
+
+ QCOMPARE(div.isNull(), false);
+ QCOMPARE(body.findAll("div").count(), 0);
+ QCOMPARE(body.findAll("p").count(), 2);
+
+ body.appendInside(div);
+
+ QCOMPARE(body.findAll("div").count(), 1);
+ QCOMPARE(body.findAll("p").count(), 3);
+}
+
+void tst_QWebElement::clear()
+{
+ QString html = "<body>"
+ "<p>"
+ "foo"
+ "</p>"
+ "<div>"
+ "<p>yeah</p>"
+ "</div>"
+ "<p>"
+ "bar"
+ "</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+
+ QCOMPARE(body.findAll("div").count(), 1);
+ QCOMPARE(body.findAll("p").count(), 3);
+ body.findFirst("div").removeAllChildren();
+ QCOMPARE(body.findAll("div").count(), 1);
+ QCOMPARE(body.findAll("p").count(), 2);
+}
+
+
+void tst_QWebElement::replaceWith()
+{
+ QString html = "<body>"
+ "<p>"
+ "foo"
+ "</p>"
+ "<div>"
+ "yeah"
+ "</div>"
+ "<p>"
+ "<span>haba</span>"
+ "</p>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+
+ QCOMPARE(body.findAll("div").count(), 1);
+ QCOMPARE(body.findAll("span").count(), 1);
+ body.findFirst("div").replace(body.findFirst("span").clone());
+ QCOMPARE(body.findAll("div").count(), 0);
+ QCOMPARE(body.findAll("span").count(), 2);
+ QCOMPARE(body.findAll("p").count(), 2);
+
+ body.findFirst("span").replace("<p><code>wow</code></p>");
+ QCOMPARE(body.findAll("p").count(), 3);
+ QCOMPARE(body.findAll("p code").count(), 1);
+ QCOMPARE(body.findFirst("p code").toPlainText(), QString("wow"));
+}
+
+void tst_QWebElement::encloseContentsWith()
+{
+ QString html = "<body>"
+ "<div>"
+ "<i>"
+ "yeah"
+ "</i>"
+ "<i>"
+ "hello"
+ "</i>"
+ "</div>"
+ "<p>"
+ "<span>foo</span>"
+ "<span>bar</span>"
+ "</p>"
+ "<u></u>"
+ "<b></b>"
+ "<em>hey</em>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+
+ body.findFirst("p").encloseContentsWith(body.findFirst("b"));
+ QCOMPARE(body.findAll("p b span").count(), 2);
+ QCOMPARE(body.findFirst("p b span").toPlainText(), QString("foo"));
+
+ body.findFirst("u").encloseContentsWith("<i></i>");
+ QCOMPARE(body.findAll("u i").count(), 1);
+ QCOMPARE(body.findFirst("u i").toPlainText(), QString());
+
+ body.findFirst("div").encloseContentsWith("<span></span>");
+ QCOMPARE(body.findAll("div span i").count(), 2);
+ QCOMPARE(body.findFirst("div span i").toPlainText(), QString("yeah"));
+
+ QString snippet = ""
+ "<table>"
+ "<tbody>"
+ "<tr>"
+ "<td></td>"
+ "<td></td>"
+ "</tr>"
+ "<tr>"
+ "<td></td>"
+ "<td></td>"
+ "<tr>"
+ "</tbody>"
+ "</table>";
+
+ body.findFirst("em").encloseContentsWith(snippet);
+ QCOMPARE(body.findFirst("em table tbody tr td").toPlainText(), QString("hey"));
+}
+
+void tst_QWebElement::encloseWith()
+{
+ QString html = "<body>"
+ "<p>"
+ "foo"
+ "</p>"
+ "<div>"
+ "yeah"
+ "</div>"
+ "<p>"
+ "<span>bar</span>"
+ "</p>"
+ "<em>hey</em>"
+ "<h1>hello</h1>"
+ "</body>";
+
+ m_mainFrame->setHtml(html);
+ QWebElement body = m_mainFrame->documentElement().findFirst("body");
+
+ body.findFirst("p").encloseWith("<br>");
+ QCOMPARE(body.findAll("br").count(), 0);
+
+ QCOMPARE(body.findAll("div").count(), 1);
+ body.findFirst("div").encloseWith(body.findFirst("span").clone());
+ QCOMPARE(body.findAll("div").count(), 1);
+ QCOMPARE(body.findAll("span").count(), 2);
+ QCOMPARE(body.findAll("p").count(), 2);
+
+ body.findFirst("div").encloseWith("<code></code>");
+ QCOMPARE(body.findAll("code").count(), 1);
+ QCOMPARE(body.findAll("code div").count(), 1);
+ QCOMPARE(body.findFirst("code div").toPlainText(), QString("yeah"));
+
+ QString snippet = ""
+ "<table>"
+ "<tbody>"
+ "<tr>"
+ "<td></td>"
+ "<td></td>"
+ "</tr>"
+ "<tr>"
+ "<td></td>"
+ "<td></td>"
+ "<tr>"
+ "</tbody>"
+ "</table>";
+
+ body.findFirst("em").encloseWith(snippet);
+ QCOMPARE(body.findFirst("table tbody tr td em").toPlainText(), QString("hey"));
+}
+
+void tst_QWebElement::nullSelect()
+{
+ m_mainFrame->setHtml("<body><p>Test");
+
+ QWebElementCollection collection = m_mainFrame->findAllElements("invalid{syn(tax;;%#$f223e>>");
+ QVERIFY(collection.count() == 0);
+}
+
+void tst_QWebElement::firstChildNextSibling()
+{
+ m_mainFrame->setHtml("<body><!--comment--><p>Test</p><!--another comment--><table>");
+
+ QWebElement body = m_mainFrame->findFirstElement("body");
+ QVERIFY(!body.isNull());
+ QWebElement p = body.firstChild();
+ QVERIFY(!p.isNull());
+ QCOMPARE(p.tagName(), QString("P"));
+ QWebElement table = p.nextSibling();
+ QVERIFY(!table.isNull());
+ QCOMPARE(table.tagName(), QString("TABLE"));
+ QVERIFY(table.nextSibling().isNull());
+}
+
+void tst_QWebElement::lastChildPreviousSibling()
+{
+ m_mainFrame->setHtml("<body><!--comment--><p>Test</p><!--another comment--><table>");
+
+ QWebElement body = m_mainFrame->findFirstElement("body");
+ QVERIFY(!body.isNull());
+ QWebElement table = body.lastChild();
+ QVERIFY(!table.isNull());
+ QCOMPARE(table.tagName(), QString("TABLE"));
+ QWebElement p = table.previousSibling();
+ QVERIFY(!p.isNull());
+ QCOMPARE(p.tagName(), QString("P"));
+ QVERIFY(p.previousSibling().isNull());
+}
+
+void tst_QWebElement::hasSetFocus()
+{
+ m_mainFrame->setHtml("<html><body>" \
+ "<input type='text' id='input1'/>" \
+ "<br>"\
+ "<input type='text' id='input2'/>" \
+ "</body></html>");
+
+ QWebElementCollection inputs = m_mainFrame->documentElement().findAll("input");
+ QWebElement input1 = inputs.at(0);
+ input1.setFocus();
+ QVERIFY(input1.hasFocus());
+
+ QWebElement input2 = inputs.at(1);
+ input2.setFocus();
+ QVERIFY(!input1.hasFocus());
+ QVERIFY(input2.hasFocus());
+}
+
+void tst_QWebElement::render()
+{
+ QString html( "<html>"
+ "<head><style>"
+ "body, iframe { margin: 0px; border: none; background: white; }"
+ "</style></head>"
+ "<body><table width='300px' height='300px' border='1'>"
+ "<tr>"
+ "<td>test"
+ "</td>"
+ "<td><img src='qrc:///image.png'>"
+ "</td>"
+ "</tr>"
+ "</table>"
+ "</body>"
+ "</html>"
+ );
+
+ QWebPage page;
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+ page.mainFrame()->setHtml(html);
+
+ waitForSignal(&page, SIGNAL(loadFinished(bool)));
+ QCOMPARE(loadSpy.count(), 1);
+
+ QSize size = page.mainFrame()->contentsSize();
+ page.setViewportSize(size);
+
+ QWebElementCollection imgs = page.mainFrame()->findAllElements("img");
+ QCOMPARE(imgs.count(), 1);
+
+ QImage resource(":/image.png");
+ QRect imageRect(0, 0, resource.width(), resource.height());
+
+ QImage testImage(resource.width(), resource.height(), QImage::Format_ARGB32);
+ QPainter painter0(&testImage);
+ painter0.fillRect(imageRect, Qt::white);
+ // render() uses pixmaps internally, and pixmaps might have bit depths
+ // other than 32, giving different pixel values due to rounding.
+ QPixmap pix = QPixmap::fromImage(resource);
+ painter0.drawPixmap(0, 0, pix);
+ painter0.end();
+
+ QImage image1(resource.width(), resource.height(), QImage::Format_ARGB32);
+ QPainter painter1(&image1);
+ painter1.fillRect(imageRect, Qt::white);
+ imgs[0].render(&painter1);
+ painter1.end();
+
+ QVERIFY(image1 == testImage);
+
+ // render image 2nd time to make sure that cached rendering works fine
+ QImage image2(resource.width(), resource.height(), QImage::Format_ARGB32);
+ QPainter painter2(&image2);
+ painter2.fillRect(imageRect, Qt::white);
+ imgs[0].render(&painter2);
+ painter2.end();
+
+ QVERIFY(image2 == testImage);
+
+ // compare table rendered through QWebElement::render to whole page table rendering
+ QRect tableRect(0, 0, 300, 300);
+ QWebElementCollection tables = page.mainFrame()->findAllElements("table");
+ QCOMPARE(tables.count(), 1);
+
+ QImage image3(300, 300, QImage::Format_ARGB32);
+ QPainter painter3(&image3);
+ painter3.fillRect(tableRect, Qt::white);
+ tables[0].render(&painter3);
+ painter3.end();
+
+ QImage image4(300, 300, QImage::Format_ARGB32);
+ QPainter painter4(&image4);
+ page.mainFrame()->render(&painter4, tableRect);
+ painter4.end();
+
+ QVERIFY(image3 == image4);
+
+ // Chunked render test reuses page rendered in image4 in previous test
+ const int chunkHeight = tableRect.height();
+ const int chunkWidth = tableRect.width() / 3;
+ QImage chunk(chunkWidth, chunkHeight, QImage::Format_ARGB32);
+ QRect chunkRect(0, 0, chunkWidth, chunkHeight);
+ for (int x = 0; x < tableRect.width(); x += chunkWidth) {
+ QPainter painter(&chunk);
+ painter.fillRect(chunkRect, Qt::white);
+ QRect chunkPaintRect(x, 0, chunkWidth, chunkHeight);
+ tables[0].render(&painter, chunkPaintRect);
+ painter.end();
+
+ QVERIFY(chunk == image4.copy(chunkPaintRect));
+ }
+}
+
+void tst_QWebElement::addElementToHead()
+{
+ m_mainFrame->setHtml("<html><head></head><body></body></html>");
+ QWebElement head = m_mainFrame->findFirstElement("head");
+ QVERIFY(!head.isNull());
+ QString append = "<script type=\"text/javascript\">var t = 0;</script>";
+ head.appendInside(append);
+ QCOMPARE(head.toInnerXml(), append);
+}
+
+QTEST_MAIN(tst_QWebElement)
+#include "tst_qwebelement.moc"
diff --git a/Source/WebKit/qt/tests/qwebelement/tst_qwebelement.qrc b/Source/WebKit/qt/tests/qwebelement/tst_qwebelement.qrc
new file mode 100644
index 0000000..7384c76
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebelement/tst_qwebelement.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+<file alias="style.css">resources/style.css</file>
+<file alias="style2.css">resources/style2.css</file>
+<file alias="image.png">resources/image.png</file>
+</qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/qwebframe/qwebframe.pro b/Source/WebKit/qt/tests/qwebframe/qwebframe.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/qwebframe.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebframe/resources/image.png b/Source/WebKit/qt/tests/qwebframe/resources/image.png
new file mode 100644
index 0000000..8d70364
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/resources/image.png
Binary files differ
diff --git a/Source/WebKit/qt/tests/qwebframe/resources/style.css b/Source/WebKit/qt/tests/qwebframe/resources/style.css
new file mode 100644
index 0000000..c05b747
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/resources/style.css
@@ -0,0 +1 @@
+#idP {color: red !important}
diff --git a/Source/WebKit/qt/tests/qwebframe/resources/test1.html b/Source/WebKit/qt/tests/qwebframe/resources/test1.html
new file mode 100644
index 0000000..b323f96
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/resources/test1.html
@@ -0,0 +1 @@
+<html><body><p>Some text 1</p></body></html>
diff --git a/Source/WebKit/qt/tests/qwebframe/resources/test2.html b/Source/WebKit/qt/tests/qwebframe/resources/test2.html
new file mode 100644
index 0000000..63ac1f6
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/resources/test2.html
@@ -0,0 +1 @@
+<html><body> <p>Some text 2</p></body></html>
diff --git a/Source/WebKit/qt/tests/qwebframe/resources/testiframe.html b/Source/WebKit/qt/tests/qwebframe/resources/testiframe.html
new file mode 100644
index 0000000..203d3d3
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/resources/testiframe.html
@@ -0,0 +1,54 @@
+</html>
+<html>
+<head>
+<title></title>
+<style type="text/css">
+<!--
+#header {
+ background: #0f0;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 800px;
+ height: 100px;
+}
+#content1 {
+ background: #ff0;
+ position: absolute;
+ top: 101px;
+ left: 0px;
+ width: 400px;
+ height: 400px;
+ overflow: scroll;
+}
+#content2 {
+ background: #ff7;
+ position: absolute;
+ top: 101px;
+ left: 401px;
+ width: 400px;
+ height: 400px;
+}
+#footer {
+ background: #0f0;
+ position: absolute;
+ top: 502px;
+ left: 0px;
+ width: 800px;
+ height: 200px;
+}
+-->
+</style>
+</head>
+<body>
+<div id="header"></div>
+<div id="content1">You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
+You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
+You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
+You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
+You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
+You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.</div>
+<iframe id="content2" name="control" src="testiframe2.html"> </iframe>
+<div id="footer"></div>
+</body>
+</html> \ No newline at end of file
diff --git a/Source/WebKit/qt/tests/qwebframe/resources/testiframe2.html b/Source/WebKit/qt/tests/qwebframe/resources/testiframe2.html
new file mode 100644
index 0000000..0d3a22f
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/resources/testiframe2.html
@@ -0,0 +1,21 @@
+</html>
+<html>
+<head>
+<title></title>
+<style type="text/css">
+<!--
+#content {
+ background: #fff;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 800px;
+ height: 800px;
+}
+-->
+</style>
+</head>
+<body>
+<div id="content"> </div>
+</body>
+</html> \ No newline at end of file
diff --git a/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp b/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp
new file mode 100644
index 0000000..3b9324d
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.cpp
@@ -0,0 +1,3645 @@
+/*
+ Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <QtTest/QtTest>
+
+#include <qwebpage.h>
+#include <qwebelement.h>
+#include <qwidget.h>
+#include <qwebview.h>
+#include <qwebframe.h>
+#include <qwebhistory.h>
+#include <QAbstractItemView>
+#include <QApplication>
+#include <QComboBox>
+#include <QPaintEngine>
+#include <QPicture>
+#include <QRegExp>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QTextCodec>
+#ifndef QT_NO_OPENSSL
+#include <qsslerror.h>
+#endif
+#include "../util.h"
+
+struct CustomType {
+ QString string;
+};
+Q_DECLARE_METATYPE(CustomType)
+
+Q_DECLARE_METATYPE(QBrush*)
+Q_DECLARE_METATYPE(QObjectList)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(Qt::BrushStyle)
+Q_DECLARE_METATYPE(QVariantList)
+Q_DECLARE_METATYPE(QVariantMap)
+
+class MyQObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
+ Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
+ Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
+ Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty)
+ Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
+ Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
+ Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
+ Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
+ Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
+ Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
+ Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
+ Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
+ Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
+ Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty)
+ Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty)
+ Q_ENUMS(Policy Strategy)
+ Q_FLAGS(Ability)
+
+public:
+ enum Policy {
+ FooPolicy = 0,
+ BarPolicy,
+ BazPolicy
+ };
+
+ enum Strategy {
+ FooStrategy = 10,
+ BarStrategy,
+ BazStrategy
+ };
+
+ enum AbilityFlag {
+ NoAbility = 0x000,
+ FooAbility = 0x001,
+ BarAbility = 0x080,
+ BazAbility = 0x200,
+ AllAbility = FooAbility | BarAbility | BazAbility
+ };
+
+ Q_DECLARE_FLAGS(Ability, AbilityFlag)
+
+ MyQObject(QObject* parent = 0)
+ : QObject(parent),
+ m_intValue(123),
+ m_variantValue(QLatin1String("foo")),
+ m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
+ m_stringValue(QLatin1String("bar")),
+ m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
+ m_brushValue(QColor(10, 20, 30, 40)),
+ m_hiddenValue(456.0),
+ m_writeOnlyValue(789),
+ m_readOnlyValue(987),
+ m_objectStar(0),
+ m_qtFunctionInvoked(-1)
+ {
+ m_variantMapValue.insert("a", QVariant(123));
+ m_variantMapValue.insert("b", QVariant(QLatin1String("foo")));
+ m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this));
+ }
+
+ ~MyQObject() { }
+
+ int intProperty() const {
+ return m_intValue;
+ }
+ void setIntProperty(int value) {
+ m_intValue = value;
+ }
+
+ QVariant variantProperty() const {
+ return m_variantValue;
+ }
+ void setVariantProperty(const QVariant &value) {
+ m_variantValue = value;
+ }
+
+ QVariantList variantListProperty() const {
+ return m_variantListValue;
+ }
+ void setVariantListProperty(const QVariantList &value) {
+ m_variantListValue = value;
+ }
+
+ QVariantMap variantMapProperty() const {
+ return m_variantMapValue;
+ }
+ void setVariantMapProperty(const QVariantMap &value) {
+ m_variantMapValue = value;
+ }
+
+ QString stringProperty() const {
+ return m_stringValue;
+ }
+ void setStringProperty(const QString &value) {
+ m_stringValue = value;
+ }
+
+ QStringList stringListProperty() const {
+ return m_stringListValue;
+ }
+ void setStringListProperty(const QStringList &value) {
+ m_stringListValue = value;
+ }
+
+ QByteArray byteArrayProperty() const {
+ return m_byteArrayValue;
+ }
+ void setByteArrayProperty(const QByteArray &value) {
+ m_byteArrayValue = value;
+ }
+
+ QBrush brushProperty() const {
+ return m_brushValue;
+ }
+ Q_INVOKABLE void setBrushProperty(const QBrush &value) {
+ m_brushValue = value;
+ }
+
+ double hiddenProperty() const {
+ return m_hiddenValue;
+ }
+ void setHiddenProperty(double value) {
+ m_hiddenValue = value;
+ }
+
+ int writeOnlyProperty() const {
+ return m_writeOnlyValue;
+ }
+ void setWriteOnlyProperty(int value) {
+ m_writeOnlyValue = value;
+ }
+
+ int readOnlyProperty() const {
+ return m_readOnlyValue;
+ }
+
+ QKeySequence shortcut() const {
+ return m_shortcut;
+ }
+ void setShortcut(const QKeySequence &seq) {
+ m_shortcut = seq;
+ }
+
+ QWebElement webElementProperty() const {
+ return m_webElement;
+ }
+
+ void setWebElementProperty(const QWebElement& element) {
+ m_webElement = element;
+ }
+
+ CustomType propWithCustomType() const {
+ return m_customType;
+ }
+ void setPropWithCustomType(const CustomType &c) {
+ m_customType = c;
+ }
+
+ QObject* objectStarProperty() const {
+ return m_objectStar;
+ }
+
+ void setObjectStarProperty(QObject* object) {
+ m_objectStar = object;
+ }
+
+
+ int qtFunctionInvoked() const {
+ return m_qtFunctionInvoked;
+ }
+
+ QVariantList qtFunctionActuals() const {
+ return m_actuals;
+ }
+
+ void resetQtFunctionInvoked() {
+ m_qtFunctionInvoked = -1;
+ m_actuals.clear();
+ }
+
+ Q_INVOKABLE void myInvokable() {
+ m_qtFunctionInvoked = 0;
+ }
+ Q_INVOKABLE void myInvokableWithIntArg(int arg) {
+ m_qtFunctionInvoked = 1;
+ m_actuals << arg;
+ }
+ Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) {
+ m_qtFunctionInvoked = 2;
+ m_actuals << arg;
+ }
+ Q_INVOKABLE void myInvokableWithFloatArg(float arg) {
+ m_qtFunctionInvoked = 3;
+ m_actuals << arg;
+ }
+ Q_INVOKABLE void myInvokableWithDoubleArg(double arg) {
+ m_qtFunctionInvoked = 4;
+ m_actuals << arg;
+ }
+ Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) {
+ m_qtFunctionInvoked = 5;
+ m_actuals << arg;
+ }
+ Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) {
+ m_qtFunctionInvoked = 6;
+ m_actuals << arg1 << arg2;
+ }
+ Q_INVOKABLE int myInvokableReturningInt() {
+ m_qtFunctionInvoked = 7;
+ return 123;
+ }
+ Q_INVOKABLE qlonglong myInvokableReturningLongLong() {
+ m_qtFunctionInvoked = 39;
+ return 456;
+ }
+ Q_INVOKABLE QString myInvokableReturningString() {
+ m_qtFunctionInvoked = 8;
+ return QLatin1String("ciao");
+ }
+ Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload
+ m_qtFunctionInvoked = 9;
+ m_actuals << arg1 << arg2;
+ }
+ Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) {
+ m_qtFunctionInvoked = 10;
+ m_actuals << policy;
+ }
+ Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) {
+ m_qtFunctionInvoked = 36;
+ m_actuals << policy;
+ }
+ Q_INVOKABLE Policy myInvokableReturningEnum() {
+ m_qtFunctionInvoked = 37;
+ return BazPolicy;
+ }
+ Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() {
+ m_qtFunctionInvoked = 38;
+ return BazPolicy;
+ }
+ Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() {
+ m_qtFunctionInvoked = 11;
+ return QVector<int>();
+ }
+ Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) {
+ m_qtFunctionInvoked = 12;
+ }
+ Q_INVOKABLE QObject* myInvokableReturningQObjectStar() {
+ m_qtFunctionInvoked = 13;
+ return this;
+ }
+ Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) {
+ m_qtFunctionInvoked = 14;
+ m_actuals << QVariant::fromValue(lst);
+ return lst;
+ }
+ Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) {
+ m_qtFunctionInvoked = 15;
+ m_actuals << v;
+ return v;
+ }
+ Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) {
+ m_qtFunctionInvoked = 16;
+ m_actuals << vm;
+ return vm;
+ }
+ Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) {
+ m_qtFunctionInvoked = 17;
+ m_actuals << QVariant::fromValue(lst);
+ return lst;
+ }
+ Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) {
+ m_qtFunctionInvoked = 18;
+ m_actuals << QVariant::fromValue(obj);
+ return obj;
+ }
+ Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) {
+ m_qtFunctionInvoked = 19;
+ m_actuals << QVariant::fromValue(brush);
+ return brush;
+ }
+ Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) {
+ m_qtFunctionInvoked = 43;
+ m_actuals << QVariant::fromValue(style);
+ }
+ Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) {
+ m_qtFunctionInvoked = 44;
+ m_actuals << QVariant::fromValue(arg);
+ }
+ Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) {
+ m_qtFunctionInvoked = 45;
+ m_actuals << QVariant::fromValue(arg);
+ }
+ Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) {
+ m_qtFunctionInvoked = 46;
+ m_actuals << QVariant::fromValue(arg);
+ }
+ Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") {
+ m_qtFunctionInvoked = 47;
+ m_actuals << QVariant::fromValue(arg1) << qVariantFromValue(arg2);
+ }
+ Q_INVOKABLE QObject& myInvokableReturningRef() {
+ m_qtFunctionInvoked = 48;
+ return *this;
+ }
+ Q_INVOKABLE const QObject& myInvokableReturningConstRef() const {
+ const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
+ return *this;
+ }
+ Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
+ const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
+ m_actuals << QVariant::fromValue(arg);
+ }
+ Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
+ const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
+ m_actuals << QVariant::fromValue(arg);
+ }
+ Q_INVOKABLE void myInvokableWithBoolArg(bool arg) {
+ m_qtFunctionInvoked = 52;
+ m_actuals << arg;
+ }
+
+ void emitMySignal() {
+ emit mySignal();
+ }
+ void emitMySignalWithIntArg(int arg) {
+ emit mySignalWithIntArg(arg);
+ }
+ void emitMySignal2(bool arg) {
+ emit mySignal2(arg);
+ }
+ void emitMySignal2() {
+ emit mySignal2();
+ }
+ void emitMySignalWithDateTimeArg(QDateTime dt) {
+ emit mySignalWithDateTimeArg(dt);
+ }
+ void emitMySignalWithRegexArg(QRegExp r) {
+ emit mySignalWithRegexArg(r);
+ }
+
+public Q_SLOTS:
+ void mySlot() {
+ m_qtFunctionInvoked = 20;
+ }
+ void mySlotWithIntArg(int arg) {
+ m_qtFunctionInvoked = 21;
+ m_actuals << arg;
+ }
+ void mySlotWithDoubleArg(double arg) {
+ m_qtFunctionInvoked = 22;
+ m_actuals << arg;
+ }
+ void mySlotWithStringArg(const QString &arg) {
+ m_qtFunctionInvoked = 23;
+ m_actuals << arg;
+ }
+
+ void myOverloadedSlot() {
+ m_qtFunctionInvoked = 24;
+ }
+ void myOverloadedSlot(QObject* arg) {
+ m_qtFunctionInvoked = 41;
+ m_actuals << QVariant::fromValue(arg);
+ }
+ void myOverloadedSlot(bool arg) {
+ m_qtFunctionInvoked = 25;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QStringList &arg) {
+ m_qtFunctionInvoked = 42;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(double arg) {
+ m_qtFunctionInvoked = 26;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(float arg) {
+ m_qtFunctionInvoked = 27;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(int arg) {
+ m_qtFunctionInvoked = 28;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QString &arg) {
+ m_qtFunctionInvoked = 29;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QColor &arg) {
+ m_qtFunctionInvoked = 30;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QBrush &arg) {
+ m_qtFunctionInvoked = 31;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QDateTime &arg) {
+ m_qtFunctionInvoked = 32;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QDate &arg) {
+ m_qtFunctionInvoked = 33;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QRegExp &arg) {
+ m_qtFunctionInvoked = 34;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QVariant &arg) {
+ m_qtFunctionInvoked = 35;
+ m_actuals << arg;
+ }
+ void myOverloadedSlot(const QWebElement &arg) {
+ m_qtFunctionInvoked = 36;
+ m_actuals << QVariant::fromValue<QWebElement>(arg);
+ }
+
+ void qscript_call(int arg) {
+ m_qtFunctionInvoked = 40;
+ m_actuals << arg;
+ }
+
+protected Q_SLOTS:
+ void myProtectedSlot() {
+ m_qtFunctionInvoked = 36;
+ }
+
+private Q_SLOTS:
+ void myPrivateSlot() { }
+
+Q_SIGNALS:
+ void mySignal();
+ void mySignalWithIntArg(int arg);
+ void mySignalWithDoubleArg(double arg);
+ void mySignal2(bool arg = false);
+ void mySignalWithDateTimeArg(QDateTime dt);
+ void mySignalWithRegexArg(QRegExp r);
+
+private:
+ int m_intValue;
+ QVariant m_variantValue;
+ QVariantList m_variantListValue;
+ QVariantMap m_variantMapValue;
+ QString m_stringValue;
+ QStringList m_stringListValue;
+ QByteArray m_byteArrayValue;
+ QBrush m_brushValue;
+ double m_hiddenValue;
+ int m_writeOnlyValue;
+ int m_readOnlyValue;
+ QKeySequence m_shortcut;
+ QWebElement m_webElement;
+ CustomType m_customType;
+ QObject* m_objectStar;
+ int m_qtFunctionInvoked;
+ QVariantList m_actuals;
+};
+
+class MyWebElementSlotOnlyObject : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(QString tagName READ tagName)
+public slots:
+ void doSomethingWithWebElement(const QWebElement& element)
+ {
+ m_tagName = element.tagName();
+ }
+
+public:
+ QString tagName() const
+ {
+ return m_tagName;
+ }
+private:
+ QString m_tagName;
+};
+
+class MyOtherQObject : public MyQObject
+{
+public:
+ MyOtherQObject(QObject* parent = 0)
+ : MyQObject(parent) { }
+};
+
+class MyEnumTestQObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString p1 READ p1)
+ Q_PROPERTY(QString p2 READ p2)
+ Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
+ Q_PROPERTY(QString p4 READ p4)
+ Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
+ Q_PROPERTY(QString p6 READ p6)
+public:
+ MyEnumTestQObject(QObject* parent = 0)
+ : QObject(parent) { }
+ QString p1() const {
+ return QLatin1String("p1");
+ }
+ QString p2() const {
+ return QLatin1String("p2");
+ }
+ QString p3() const {
+ return QLatin1String("p3");
+ }
+ QString p4() const {
+ return QLatin1String("p4");
+ }
+ QString p5() const {
+ return QLatin1String("p5");
+ }
+ QString p6() const {
+ return QLatin1String("p5");
+ }
+public Q_SLOTS:
+ void mySlot() { }
+ void myOtherSlot() { }
+Q_SIGNALS:
+ void mySignal();
+};
+
+class tst_QWebFrame : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebFrame();
+ virtual ~tst_QWebFrame();
+ bool eventFilter(QObject* watched, QEvent* event);
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void horizontalScrollAfterBack();
+ void getSetStaticProperty();
+ void getSetDynamicProperty();
+ void getSetChildren();
+ void callQtInvokable();
+ void connectAndDisconnect();
+ void classEnums();
+ void classConstructor();
+ void overrideInvokable();
+ void transferInvokable();
+ void findChild();
+ void findChildren();
+ void overloadedSlots();
+ void webElementSlotOnly();
+ void enumerate_data();
+ void enumerate();
+ void objectDeleted();
+ void typeConversion();
+ void arrayObjectEnumerable();
+ void symmetricUrl();
+ void progressSignal();
+ void urlChange();
+ void domCycles();
+ void requestedUrl();
+ void requestedUrlAfterSetAndLoadFailures();
+ void javaScriptWindowObjectCleared_data();
+ void javaScriptWindowObjectCleared();
+ void javaScriptWindowObjectClearedOnEvaluate();
+ void setHtml();
+ void setHtmlWithResource();
+ void setHtmlWithBaseURL();
+ void setHtmlWithJSAlert();
+ void ipv6HostEncoding();
+ void metaData();
+#if !defined(Q_WS_MAEMO_5) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_COMBOBOX)
+ // as maemo 5 && symbian do not use QComboBoxes to implement the popups
+ // this test does not make sense for it.
+ void popupFocus();
+#endif
+ void inputFieldFocus();
+ void hitTestContent();
+ void jsByteArray();
+ void ownership();
+ void nullValue();
+ void baseUrl_data();
+ void baseUrl();
+ void hasSetFocus();
+ void render();
+ void renderHints();
+ void scrollPosition();
+ void scrollToAnchor();
+ void scrollbarsOff();
+ void evaluateWillCauseRepaint();
+ void qObjectWrapperWithSameIdentity();
+ void introspectQtMethods_data();
+ void introspectQtMethods();
+ void setContent_data();
+ void setContent();
+ void setCacheLoadControlAttribute();
+ void setUrlWithPendingLoads();
+ void setUrlWithFragment_data();
+ void setUrlWithFragment();
+ void setUrlToEmpty();
+ void setUrlToInvalid();
+ void setUrlHistory();
+ void setUrlSameUrl();
+ void setUrlThenLoads_data();
+ void setUrlThenLoads();
+
+private:
+ QString evalJS(const QString&s) {
+ // Convert an undefined return variant to the string "undefined"
+ QVariant ret = evalJSV(s);
+ if (ret.userType() == QMetaType::Void)
+ return "undefined";
+ else
+ return ret.toString();
+ }
+ QVariant evalJSV(const QString &s) {
+ return m_page->mainFrame()->evaluateJavaScript(s);
+ }
+
+ QString evalJS(const QString&s, QString& type) {
+ return evalJSV(s, type).toString();
+ }
+ QVariant evalJSV(const QString &s, QString& type) {
+ // As a special measure, if we get an exception we set the type to 'error'
+ // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
+ // Similarly, an array is an object, but we'd prefer to have a type of 'array'
+ // Also, consider a QMetaType::Void QVariant to be undefined
+ QString escaped = s;
+ escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
+ evalJS("var retvalue;\
+ var typevalue; \
+ try {\
+ retvalue = eval('" + escaped + "'); \
+ typevalue = typeof retvalue; \
+ if (retvalue instanceof Array) \
+ typevalue = 'array'; \
+ } \
+ catch(e) {\
+ retvalue = e.name + ': ' + e.message;\
+ typevalue = 'error';\
+ }");
+ QVariant ret = evalJSV("retvalue");
+ if (ret.userType() != QMetaType::Void)
+ type = evalJS("typevalue");
+ else {
+ ret = QString("undefined");
+ type = sUndefined;
+ }
+ evalJS("delete retvalue; delete typevalue");
+ return ret;
+ }
+ QObject* firstChildByClassName(QObject* parent, const char* className) {
+ const QObjectList & children = parent->children();
+ foreach (QObject* child, children) {
+ if (!strcmp(child->metaObject()->className(), className)) {
+ return child;
+ }
+ }
+ return 0;
+ }
+
+ const QString sTrue;
+ const QString sFalse;
+ const QString sUndefined;
+ const QString sArray;
+ const QString sFunction;
+ const QString sError;
+ const QString sString;
+ const QString sObject;
+ const QString sNumber;
+
+private:
+ QWebView* m_view;
+ QWebPage* m_page;
+ MyQObject* m_myObject;
+ QWebView* m_inputFieldsTestView;
+ int m_inputFieldTestPaintCount;
+};
+
+tst_QWebFrame::tst_QWebFrame()
+ : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"),
+ sString("string"), sObject("object"), sNumber("number"), m_inputFieldsTestView(0), m_inputFieldTestPaintCount(0)
+{
+}
+
+tst_QWebFrame::~tst_QWebFrame()
+{
+}
+
+bool tst_QWebFrame::eventFilter(QObject* watched, QEvent* event)
+{
+ // used on the inputFieldFocus test
+ if (watched == m_inputFieldsTestView) {
+ if (event->type() == QEvent::Paint)
+ m_inputFieldTestPaintCount++;
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+void tst_QWebFrame::init()
+{
+ m_view = new QWebView();
+ m_page = m_view->page();
+ m_myObject = new MyQObject();
+ m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
+}
+
+void tst_QWebFrame::cleanup()
+{
+ delete m_view;
+ delete m_myObject;
+}
+
+void tst_QWebFrame::getSetStaticProperty()
+{
+ m_page->mainFrame()->setHtml("<html><head><body></body></html>");
+ QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
+
+ // initial value (set in MyQObject constructor)
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.intProperty", type);
+ QCOMPARE(type, sNumber);
+ QCOMPARE(ret.type(), QVariant::Double);
+ QCOMPARE(ret.toInt(), 123);
+ }
+ QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
+
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.variantProperty", type);
+ QCOMPARE(type, sString);
+ QCOMPARE(ret.type(), QVariant::String);
+ QCOMPARE(ret.toString(), QLatin1String("foo"));
+ }
+ QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
+
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.stringProperty", type);
+ QCOMPARE(type, sString);
+ QCOMPARE(ret.type(), QVariant::String);
+ QCOMPARE(ret.toString(), QLatin1String("bar"));
+ }
+ QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
+
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.variantListProperty", type);
+ QCOMPARE(type, sArray);
+ QCOMPARE(ret.type(), QVariant::List);
+ QVariantList vl = ret.value<QVariantList>();
+ QCOMPARE(vl.size(), 2);
+ QCOMPARE(vl.at(0).toInt(), 123);
+ QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
+ }
+ QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
+ QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
+ QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
+
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.variantMapProperty", type);
+ QCOMPARE(type, sObject);
+ QCOMPARE(ret.type(), QVariant::Map);
+ QVariantMap vm = ret.value<QVariantMap>();
+ QCOMPARE(vm.size(), 3);
+ QCOMPARE(vm.value("a").toInt(), 123);
+ QCOMPARE(vm.value("b").toString(), QLatin1String("foo"));
+ QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject));
+ }
+ QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue);
+ QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue);
+ QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue);
+
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.stringListProperty", type);
+ QCOMPARE(type, sArray);
+ QCOMPARE(ret.type(), QVariant::List);
+ QVariantList vl = ret.value<QVariantList>();
+ QCOMPARE(vl.size(), 2);
+ QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
+ QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
+ }
+ QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
+ QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
+ QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
+ QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
+
+ // property change in C++ should be reflected in script
+ m_myObject->setIntProperty(456);
+ QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
+ m_myObject->setIntProperty(789);
+ QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
+
+ m_myObject->setVariantProperty(QLatin1String("bar"));
+ QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
+ m_myObject->setVariantProperty(42);
+ QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
+ m_myObject->setVariantProperty(QVariant::fromValue(QBrush()));
+//XFAIL
+// QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant);
+
+ m_myObject->setStringProperty(QLatin1String("baz"));
+ QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
+ m_myObject->setStringProperty(QLatin1String("zab"));
+ QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
+
+ // property change in script should be reflected in C++
+ QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
+ QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
+ QCOMPARE(m_myObject->intProperty(), 123);
+ QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
+ "myObject.intProperty == 0"), sTrue);
+ QCOMPARE(m_myObject->intProperty(), 0);
+ QCOMPARE(evalJS("myObject.intProperty = '123';"
+ "myObject.intProperty == 123"), sTrue);
+ QCOMPARE(m_myObject->intProperty(), 123);
+
+ QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
+ QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
+ QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
+ QCOMPARE(evalJS("myObject.stringProperty = 123;"
+ "myObject.stringProperty"), QLatin1String("123"));
+ QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
+ QCOMPARE(evalJS("myObject.stringProperty = null"), QString());
+ QCOMPARE(evalJS("myObject.stringProperty"), QString());
+ QCOMPARE(m_myObject->stringProperty(), QString());
+ QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined);
+ QCOMPARE(evalJS("myObject.stringProperty"), QString());
+ QCOMPARE(m_myObject->stringProperty(), QString());
+
+ QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);"
+ "myObject.variantProperty").toDouble(), 1234.0);
+ QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0);
+
+ QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);"
+ "myObject.variantProperty"), sTrue);
+ QCOMPARE(m_myObject->variantProperty().toBool(), true);
+
+ QCOMPARE(evalJS("myObject.variantProperty = null;"
+ "myObject.variantProperty.valueOf()"), sUndefined);
+ QCOMPARE(m_myObject->variantProperty(), QVariant());
+ QCOMPARE(evalJS("myObject.variantProperty = undefined;"
+ "myObject.variantProperty.valueOf()"), sUndefined);
+ QCOMPARE(m_myObject->variantProperty(), QVariant());
+
+ QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
+ "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
+ QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
+ QCOMPARE(evalJS("myObject.variantProperty = 42;"
+ "myObject.variantProperty").toDouble(), 42.0);
+ QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
+
+ QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
+ "myObject.variantListProperty.length == 3"), sTrue);
+ QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
+ QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
+ QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
+
+ QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
+ "myObject.stringListProperty.length == 3"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
+ QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
+ QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
+ QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
+ QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
+ evalJS("myObject.webElementProperty=document.body;");
+ QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY"));
+
+ // try to delete
+ QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
+ QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
+
+ QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
+ QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
+
+ // custom property
+ QCOMPARE(evalJS("myObject.customProperty"), sUndefined);
+ QCOMPARE(evalJS("myObject.customProperty = 123;"
+ "myObject.customProperty == 123"), sTrue);
+ QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty");
+ QCOMPARE(v.type(), QVariant::Double);
+ QCOMPARE(v.toInt(), 123);
+
+ // non-scriptable property
+ QCOMPARE(m_myObject->hiddenProperty(), 456.0);
+ QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
+ QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
+ "myObject.hiddenProperty == 123"), sTrue);
+ QCOMPARE(m_myObject->hiddenProperty(), 456.0);
+
+ // write-only property
+ QCOMPARE(m_myObject->writeOnlyProperty(), 789);
+ QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
+ QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
+ "typeof myObject.writeOnlyProperty"), sUndefined);
+ QCOMPARE(m_myObject->writeOnlyProperty(), 123);
+
+ // read-only property
+ QCOMPARE(m_myObject->readOnlyProperty(), 987);
+ QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
+ QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
+ "myObject.readOnlyProperty == 987"), sTrue);
+ QCOMPARE(m_myObject->readOnlyProperty(), 987);
+
+ // QObject* property
+ m_myObject->setObjectStarProperty(0);
+ QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0);
+ QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
+ QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse);
+ QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue);
+ QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"),
+ sUndefined);
+ m_myObject->setObjectStarProperty(this);
+ QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
+ QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue);
+ QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue);
+}
+
+void tst_QWebFrame::getSetDynamicProperty()
+{
+ // initially the object does not have the property
+ // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
+
+ //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
+ QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
+
+ // add a dynamic property in C++
+ QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
+ //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
+ QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
+
+ // property change in script should be reflected in C++
+ QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
+ "myObject.dynamicProperty"), QLatin1String("foo"));
+ QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
+
+ // delete the property (XFAIL - can't delete properties)
+ QEXPECT_FAIL("", "can't delete properties", Continue);
+ QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
+ /*
+ QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
+ QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
+ // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
+ QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
+ */
+}
+
+void tst_QWebFrame::getSetChildren()
+{
+ // initially the object does not have the child
+ // (again, no hasOwnProperty)
+
+ //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
+ QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
+
+ // add a child
+ MyQObject* child = new MyQObject(m_myObject);
+ child->setObjectName("child");
+// QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
+
+ // add a grandchild
+ MyQObject* grandChild = new MyQObject(child);
+ grandChild->setObjectName("grandChild");
+// QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
+ QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
+
+ // delete grandchild
+ delete grandChild;
+// QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
+ QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
+
+ // delete child
+ delete child;
+// QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
+ QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
+}
+
+Q_DECLARE_METATYPE(QVector<int>)
+Q_DECLARE_METATYPE(QVector<double>)
+Q_DECLARE_METATYPE(QVector<QString>)
+
+void tst_QWebFrame::callQtInvokable()
+{
+ qRegisterMetaType<QObjectList>();
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ // extra arguments should silently be ignored
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
+ QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
+ QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
+ QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
+ QCOMPARE(type, sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
+ QCOMPARE(type, sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
+ }
+
+ // calling function that returns (const)ref
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
+ QCOMPARE(ret, sUndefined);
+ //QVERIFY(!m_engine->hasUncaughtException());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
+ QCOMPARE(ret, sUndefined);
+ //QVERIFY(!m_engine->hasUncaughtException());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
+ QCOMPARE(type, sObject);
+ QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(type, sArray);
+ QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
+ QVariantList vl = qvariant_cast<QVariantList>(ret);
+ QCOMPARE(vl.count(), 1);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ m_myObject->setVariantProperty(QVariant(123));
+ QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
+ QCOMPARE(type, sNumber);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
+ QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
+ QCOMPARE(ret.toInt(),123);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type);
+ QCOMPARE(type, sObject);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
+ QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type);
+ QCOMPARE(type, sObject);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
+ QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
+ }
+
+ /* XFAIL - variant support
+ m_myObject->resetQtFunctionInvoked();
+ {
+ m_myObject->setVariantProperty(QVariant::fromValue(QBrush()));
+ QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
+ QVERIFY(ret.isVariant());
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
+ QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
+ }
+ */
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
+ QCOMPARE(type, sNumber);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
+ QCOMPARE(ret.userType(), int(QMetaType::Double));
+ QCOMPARE(ret.toInt(),123);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
+
+ QVariantMap vmap = qvariant_cast<QVariantMap>(v);
+ QCOMPARE(vmap.keys().size(), 2);
+ QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
+ QCOMPARE(vmap.value("a"), QVariant(123));
+ QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
+ QCOMPARE(vmap.value("b"), QVariant("ciao"));
+
+ QCOMPARE(type, sObject);
+
+ QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
+ vmap = qvariant_cast<QVariantMap>(ret);
+ QCOMPARE(vmap.keys().size(), 2);
+ QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
+ QCOMPARE(vmap.value("a"), QVariant(123));
+ QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
+ QCOMPARE(vmap.value("b"), QVariant("ciao"));
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
+ QList<int> ilst = qvariant_cast<QList<int> >(v);
+ QCOMPARE(ilst.size(), 2);
+ QCOMPARE(ilst.at(0), 1);
+ QCOMPARE(ilst.at(1), 5);
+
+ QCOMPARE(type, sArray);
+ QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
+ QVariantList vlst = qvariant_cast<QVariantList>(ret);
+ QCOMPARE(vlst.size(), 2);
+ QCOMPARE(vlst.at(0).toInt(), 1);
+ QCOMPARE(vlst.at(1).toInt(), 5);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
+ QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
+
+ QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
+ QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
+
+ QCOMPARE(type, sObject);
+ }
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ // no implicit conversion from integer to QObject*
+ QString type;
+ evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
+ QCOMPARE(type, sError);
+ }
+
+ /*
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString fun = evalJS("myObject.myInvokableWithQBrushArg");
+ Q_ASSERT(fun.isFunction());
+ QColor color(10, 20, 30, 40);
+ // QColor should be converted to a QBrush
+ QVariant ret = fun.call(QString(), QStringList()
+ << qScriptValueFromValue(m_engine, color));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QVariant v = m_myObject->qtFunctionActuals().at(0);
+ QCOMPARE(v.userType(), int(QMetaType::QBrush));
+ QCOMPARE(qvariant_cast<QColor>(v), color);
+
+ QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
+ }
+ */
+
+ // private slots should not be part of the QObject binding
+ QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
+
+ // protected slots should be fine
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myProtectedSlot()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
+
+ // call with too few arguments
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
+ }
+
+ // call function where not all types have been registered
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ }
+
+ // call function with incompatible argument type
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ }
+}
+
+void tst_QWebFrame::connectAndDisconnect()
+{
+ // connect(function)
+ QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
+ QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
+ QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
+
+ {
+ QString type;
+ evalJS("myObject.mySignal.connect(123)", type);
+ QCOMPARE(type, sError);
+ }
+
+ evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }");
+
+ QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
+
+ evalJS("gotSignal = false");
+ evalJS("myObject.mySignal()");
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
+ QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
+ QCOMPARE(evalJS("slotThisObject == window"), sTrue);
+
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignal();
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
+
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
+
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignalWithIntArg(123);
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
+ QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
+
+ QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
+ {
+ QString type;
+ evalJS("myObject.mySignal.disconnect(myHandler)", type);
+ QCOMPARE(type, sError);
+ }
+
+ evalJS("gotSignal = false");
+ QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
+ m_myObject->emitMySignal2(true);
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
+ QCOMPARE(evalJS("signalArgs[0]"), sTrue);
+
+ QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
+
+ QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
+ QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
+ QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
+
+ QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
+
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignal2();
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+
+ QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
+
+ // connect(object, function)
+ evalJS("otherObject = { name:'foo' }");
+ QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
+ QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignal();
+ QCOMPARE(evalJS("gotSignal"), sFalse);
+
+ {
+ QString type;
+ evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
+ QCOMPARE(type, sError);
+ }
+
+ QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignal();
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
+ QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject"));
+ QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
+ QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
+ QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
+
+ evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
+ QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignal2(true);
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
+ QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
+ QCOMPARE(evalJS("signalSender == myObject"), sTrue);
+ QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
+ QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
+
+ QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
+ evalJS("gotSignal = false");
+ m_myObject->emitMySignal2(true);
+ QCOMPARE(evalJS("gotSignal"), sTrue);
+ QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
+ QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
+ QCOMPARE(evalJS("signalSender == myObject"), sTrue);
+ QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
+
+ // connect(obj, string)
+ QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
+ QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
+ QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
+ QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
+
+ // check that emitting signals from script works
+
+ // no arguments
+ QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
+ QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
+
+ // one argument
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
+
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
+
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
+
+ // connecting to overloaded slot
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
+
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
+ QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
+
+ // erroneous input
+ {
+ // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
+ QString type;
+ QString ret = evalJS("(function() { }).connect()", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("(function() { }).connect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: 'undefined' is not a function"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokable.connect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("myObject.mySignal.connect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("myObject.mySignal.disconnect()", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
+ }
+
+ /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
+ {
+ QString type;
+ QString ret = evalJS("(function() { }).disconnect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
+ }
+ */
+
+ {
+ QString type;
+ QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
+ }
+
+ // when the wrapper dies, the connection stays alive
+ QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
+ m_myObject->resetQtFunctionInvoked();
+ m_myObject->emitMySignal();
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
+ evalJS("myObject = null");
+ evalJS("gc()");
+ m_myObject->resetQtFunctionInvoked();
+ m_myObject->emitMySignal();
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
+}
+
+void tst_QWebFrame::classEnums()
+{
+ // We don't do the meta thing currently, unfortunately!!!
+ /*
+ QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
+ m_engine->globalObject().setProperty("MyQObject", myClass);
+
+ QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()),
+ MyQObject::FooPolicy);
+ QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()),
+ MyQObject::BarPolicy);
+ QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()),
+ MyQObject::BazPolicy);
+
+ QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()),
+ MyQObject::FooStrategy);
+ QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()),
+ MyQObject::BarStrategy);
+ QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()),
+ MyQObject::BazStrategy);
+
+ QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()),
+ MyQObject::NoAbility);
+ QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()),
+ MyQObject::FooAbility);
+ QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()),
+ MyQObject::BarAbility);
+ QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()),
+ MyQObject::BazAbility);
+ QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()),
+ MyQObject::AllAbility);
+
+ // enums from Qt are inherited through prototype
+ QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()),
+ Qt::StrongFocus);
+ QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()),
+ Qt::Key_Left);
+
+ QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject"));
+
+ qRegisterMetaType<MyQObject::Policy>("Policy");
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
+
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
+
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QVariant ret = evalJS("myObject.myInvokableReturningEnum()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
+ QCOMPARE(ret.isVariant());
+ }
+ m_myObject->resetQtFunctionInvoked();
+ {
+ QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
+ QCOMPARE(ret.isNumber());
+ }
+ */
+}
+
+void tst_QWebFrame::classConstructor()
+{
+ /*
+ QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
+ m_engine->globalObject().setProperty("MyQObject", myClass);
+
+ QString myObj = evalJS("myObj = MyQObject()");
+ QObject* qobj = myObj.toQObject();
+ QVERIFY(qobj != 0);
+ QCOMPARE(qobj->metaObject()->className(), "MyQObject");
+ QCOMPARE(qobj->parent(), (QObject*)0);
+
+ QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
+ m_engine->globalObject().setProperty("QObject", qobjectClass);
+
+ QString otherObj = evalJS("otherObj = QObject(myObj)");
+ QObject* qqobj = otherObj.toQObject();
+ QVERIFY(qqobj != 0);
+ QCOMPARE(qqobj->metaObject()->className(), "QObject");
+ QCOMPARE(qqobj->parent(), qobj);
+
+ delete qobj;
+ */
+}
+
+void tst_QWebFrame::overrideInvokable()
+{
+ m_myObject->resetQtFunctionInvoked();
+ QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+
+ /* XFAIL - can't write to functions with RuntimeObject
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myInvokable = function() { window.a = 123; }");
+ evalJS("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ QCOMPARE(evalJS("window.a").toDouble(), 123.0);
+
+ evalJS("myObject.myInvokable = function() { window.a = 456; }");
+ evalJS("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
+ QCOMPARE(evalJS("window.a").toDouble(), 456.0);
+ */
+
+ evalJS("delete myObject.myInvokable");
+ evalJS("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+
+ /* XFAIL - ditto
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
+ evalJS("myObject.myInvokable(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ */
+
+ evalJS("delete myObject.myInvokable");
+ m_myObject->resetQtFunctionInvoked();
+ // this form (with the '()') is read-only
+ evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
+ evalJS("myObject.myInvokable()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+}
+
+void tst_QWebFrame::transferInvokable()
+{
+ /* XFAIL - can't put to functions with RuntimeObject
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.foozball = myObject.myInvokable");
+ evalJS("myObject.foozball()");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.foozball = myObject.myInvokableWithIntArg");
+ evalJS("myObject.foozball(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
+ evalJS("myObject.myInvokable(123)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
+
+ MyOtherQObject other;
+ m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other);
+ evalJS("myOtherObject.foo = myObject.foozball");
+ other.resetQtFunctionInvoked();
+ evalJS("myOtherObject.foo(456)");
+ QCOMPARE(other.qtFunctionInvoked(), 1);
+ */
+}
+
+void tst_QWebFrame::findChild()
+{
+ /*
+ QObject* child = new QObject(m_myObject);
+ child->setObjectName(QLatin1String("myChildObject"));
+
+ {
+ QString result = evalJS("myObject.findChild('noSuchChild')");
+ QCOMPARE(result.isNull());
+ }
+
+ {
+ QString result = evalJS("myObject.findChild('myChildObject')");
+ QCOMPARE(result.isQObject());
+ QCOMPARE(result.toQObject(), child);
+ }
+
+ delete child;
+ */
+}
+
+void tst_QWebFrame::findChildren()
+{
+ /*
+ QObject* child = new QObject(m_myObject);
+ child->setObjectName(QLatin1String("myChildObject"));
+
+ {
+ QString result = evalJS("myObject.findChildren('noSuchChild')");
+ QCOMPARE(result.isArray());
+ QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0);
+ }
+
+ {
+ QString result = evalJS("myObject.findChildren('myChildObject')");
+ QCOMPARE(result.isArray());
+ QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
+ QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
+ }
+
+ QObject* namelessChild = new QObject(m_myObject);
+
+ {
+ QString result = evalJS("myObject.findChildren('myChildObject')");
+ QCOMPARE(result.isArray());
+ QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
+ QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
+ }
+
+ QObject* anotherChild = new QObject(m_myObject);
+ anotherChild->setObjectName(QLatin1String("anotherChildObject"));
+
+ {
+ QString result = evalJS("myObject.findChildren('anotherChildObject')");
+ QCOMPARE(result.isArray());
+ QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
+ QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
+ }
+
+ anotherChild->setObjectName(QLatin1String("myChildObject"));
+ {
+ QString result = evalJS("myObject.findChildren('myChildObject')");
+ QCOMPARE(result.isArray());
+ QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0);
+ QObject* o1 = result.property(QLatin1String("0")).toQObject();
+ QObject* o2 = result.property(QLatin1String("1")).toQObject();
+ if (o1 != child) {
+ QCOMPARE(o1, anotherChild);
+ QCOMPARE(o2, child);
+ } else {
+ QCOMPARE(o1, child);
+ QCOMPARE(o2, anotherChild);
+ }
+ }
+
+ // find all
+ {
+ QString result = evalJS("myObject.findChildren()");
+ QVERIFY(result.isArray());
+ int count = 3;
+ QCOMPARE(result.property("length"), QLatin1String(count);
+ for (int i = 0; i < 3; ++i) {
+ QObject* o = result.property(i).toQObject();
+ if (o == namelessChild || o == child || o == anotherChild)
+ --count;
+ }
+ QVERIFY(count == 0);
+ }
+
+ delete anotherChild;
+ delete namelessChild;
+ delete child;
+ */
+}
+
+void tst_QWebFrame::overloadedSlots()
+{
+ // should pick myOverloadedSlot(double)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(10)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
+
+ // should pick myOverloadedSlot(double)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(10.0)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
+
+ // should pick myOverloadedSlot(QString)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot('10')");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
+
+ // should pick myOverloadedSlot(bool)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(true)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
+
+ // should pick myOverloadedSlot(QDateTime)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(new Date())");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
+
+ // should pick myOverloadedSlot(QRegExp)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(new RegExp())");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
+
+ // should pick myOverloadedSlot(QVariant)
+ /* XFAIL
+ m_myObject->resetQtFunctionInvoked();
+ QString f = evalJS("myObject.myOverloadedSlot");
+ f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
+ */
+
+ // should pick myOverloadedSlot(QRegExp)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(document.body)");
+ QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=37319", Continue);
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
+
+ // should pick myOverloadedSlot(QObject*)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(myObject)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
+
+ // should pick myOverloadedSlot(QObject*)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(null)");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
+
+ // should pick myOverloadedSlot(QStringList)
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(['hello'])");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
+}
+
+void tst_QWebFrame::enumerate_data()
+{
+ QTest::addColumn<QStringList>("expectedNames");
+
+ QTest::newRow("enumerate all")
+ << (QStringList()
+ // meta-object-defined properties:
+ // inherited
+ << "objectName"
+ // non-inherited
+ << "p1" << "p2" << "p4" << "p6"
+ // dynamic properties
+ << "dp1" << "dp2" << "dp3"
+ // inherited slots
+ << "destroyed(QObject*)" << "destroyed()"
+ << "deleteLater()"
+ // not included because it's private:
+ // << "_q_reregisterTimers(void*)"
+ // signals
+ << "mySignal()"
+ // slots
+ << "mySlot()" << "myOtherSlot()");
+}
+
+void tst_QWebFrame::enumerate()
+{
+ QFETCH(QStringList, expectedNames);
+
+ MyEnumTestQObject enumQObject;
+ // give it some dynamic properties
+ enumQObject.setProperty("dp1", "dp1");
+ enumQObject.setProperty("dp2", "dp2");
+ enumQObject.setProperty("dp3", "dp3");
+ m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
+
+ // enumerate in script
+ {
+ evalJS("var enumeratedProperties = []");
+ evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
+ QStringList result = evalJSV("enumeratedProperties").toStringList();
+ QCOMPARE(result.size(), expectedNames.size());
+ for (int i = 0; i < expectedNames.size(); ++i)
+ QCOMPARE(result.at(i), expectedNames.at(i));
+ }
+}
+
+void tst_QWebFrame::objectDeleted()
+{
+ MyQObject* qobj = new MyQObject();
+ m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
+ evalJS("bar.objectName = 'foo';");
+ QCOMPARE(qobj->objectName(), QLatin1String("foo"));
+ evalJS("bar.intProperty = 123;");
+ QCOMPARE(qobj->intProperty(), 123);
+ qobj->resetQtFunctionInvoked();
+ evalJS("bar.myInvokable.call(bar);");
+ QCOMPARE(qobj->qtFunctionInvoked(), 0);
+
+ // do this, to ensure that we cache that it implements call
+ evalJS("bar()");
+
+ // now delete the object
+ delete qobj;
+
+ QCOMPARE(evalJS("typeof bar"), sObject);
+
+ // any attempt to access properties of the object should result in an exception
+ {
+ QString type;
+ QString ret = evalJS("bar.objectName", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("bar.objectName = 'foo'", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
+ }
+
+ // myInvokable is stored in member table (since we've accessed it before deletion)
+ {
+ QString type;
+ evalJS("bar.myInvokable", type);
+ QCOMPARE(type, sFunction);
+ }
+
+ {
+ QString type;
+ QString ret = evalJS("bar.myInvokable.call(bar);", type);
+ ret = evalJS("bar.myInvokable(bar)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
+ }
+ // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
+ {
+ QString type;
+ QString ret = evalJS("bar.myInvokableWithIntArg", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
+ }
+
+ // access from script
+ evalJS("window.o = bar;");
+ {
+ QString type;
+ QString ret = evalJS("o.objectName", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("o.myInvokable()", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
+ }
+ {
+ QString type;
+ QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
+ QCOMPARE(type, sError);
+ QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
+ }
+}
+
+void tst_QWebFrame::typeConversion()
+{
+ m_myObject->resetQtFunctionInvoked();
+
+ QDateTime localdt(QDate(2008,1,18), QTime(12,31,0));
+ QDateTime utclocaldt = localdt.toUTC();
+ QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC);
+
+ // Dates in JS (default to local)
+ evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
+
+ m_myObject->resetQtFunctionInvoked();
+ evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
+ QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
+ QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
+ QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
+
+ // Pushing QDateTimes into JS
+ // Local
+ evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
+ evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
+ m_myObject->emitMySignalWithDateTimeArg(localdt);
+ QCOMPARE(evalJS("window.__date_equals"), sTrue);
+ evalJS("delete window.__date_equals");
+ m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
+ QCOMPARE(evalJS("window.__date_equals"), sTrue);
+ evalJS("delete window.__date_equals");
+ evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
+
+ // UTC
+ evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
+ evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
+ m_myObject->emitMySignalWithDateTimeArg(utcdt);
+ QCOMPARE(evalJS("window.__date_equals"), sTrue);
+ evalJS("delete window.__date_equals");
+ evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
+
+ // ### RegExps
+}
+
+class StringListTestObject : public QObject {
+ Q_OBJECT
+public Q_SLOTS:
+ QVariant stringList()
+ {
+ return QStringList() << "Q" << "t";
+ };
+};
+
+void tst_QWebFrame::arrayObjectEnumerable()
+{
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ QObject* qobject = new StringListTestObject();
+ frame->addToJavaScriptWindowObject("test", qobject, QScriptEngine::ScriptOwnership);
+
+ const QString script("var stringArray = test.stringList();"
+ "var result = '';"
+ "for (var i in stringArray) {"
+ " result += stringArray[i];"
+ "}"
+ "result;");
+ QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt"));
+}
+
+void tst_QWebFrame::symmetricUrl()
+{
+ QVERIFY(m_view->url().isEmpty());
+
+ QCOMPARE(m_view->history()->count(), 0);
+
+ QUrl dataUrl("data:text/html,<h1>Test");
+
+ m_view->setUrl(dataUrl);
+ QCOMPARE(m_view->url(), dataUrl);
+ QCOMPARE(m_view->history()->count(), 0);
+
+ // loading is _not_ immediate, so the text isn't set just yet.
+ QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty());
+
+ ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(m_view->history()->count(), 1);
+ QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test"));
+
+ QUrl dataUrl2("data:text/html,<h1>Test2");
+ QUrl dataUrl3("data:text/html,<h1>Test3");
+
+ m_view->setUrl(dataUrl2);
+ m_view->setUrl(dataUrl3);
+
+ QCOMPARE(m_view->url(), dataUrl3);
+
+ ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(m_view->history()->count(), 2);
+
+ QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3"));
+}
+
+void tst_QWebFrame::progressSignal()
+{
+ QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int)));
+
+ QUrl dataUrl("data:text/html,<h1>Test");
+ m_view->setUrl(dataUrl);
+
+ ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
+
+ QVERIFY(progressSpy.size() >= 2);
+
+ // WebKit defines initialProgressValue as 10%, not 0%
+ QCOMPARE(progressSpy.first().first().toInt(), 10);
+
+ // But we always end at 100%
+ QCOMPARE(progressSpy.last().first().toInt(), 100);
+}
+
+void tst_QWebFrame::urlChange()
+{
+ QSignalSpy urlSpy(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
+
+ QUrl dataUrl("data:text/html,<h1>Test");
+ m_view->setUrl(dataUrl);
+
+ ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
+
+ QCOMPARE(urlSpy.size(), 1);
+
+ QUrl dataUrl2("data:text/html,<html><head><title>title</title></head><body><h1>Test</body></html>");
+ m_view->setUrl(dataUrl2);
+
+ ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
+
+ QCOMPARE(urlSpy.size(), 2);
+}
+
+
+void tst_QWebFrame::domCycles()
+{
+ m_view->setHtml("<html><body>");
+ QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
+ QVERIFY(v.type() == QVariant::Map);
+}
+
+class FakeReply : public QNetworkReply {
+ Q_OBJECT
+
+public:
+ FakeReply(const QNetworkRequest& request, QObject* parent = 0)
+ : QNetworkReply(parent)
+ {
+ setOperation(QNetworkAccessManager::GetOperation);
+ setRequest(request);
+ if (request.url() == QUrl("qrc:/test1.html")) {
+ setHeader(QNetworkRequest::LocationHeader, QString("qrc:/test2.html"));
+ setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html"));
+ }
+#ifndef QT_NO_OPENSSL
+ else if (request.url() == QUrl("qrc:/fake-ssl-error.html"))
+ setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error !")); // force a ssl error
+#endif
+ else if (request.url().host() == QLatin1String("abcdef.abcdef"))
+ setError(QNetworkReply::HostNotFoundError, tr("Invalid URL"));
+
+ open(QIODevice::ReadOnly);
+ QTimer::singleShot(0, this, SLOT(timeout()));
+ }
+ ~FakeReply()
+ {
+ close();
+ }
+ virtual void abort() {}
+ virtual void close() {}
+
+protected:
+ qint64 readData(char*, qint64)
+ {
+ return 0;
+ }
+
+private slots:
+ void timeout()
+ {
+ if (request().url() == QUrl("qrc://test1.html"))
+ emit error(this->error());
+ else if (request().url() == QUrl("http://abcdef.abcdef/"))
+ emit metaDataChanged();
+#ifndef QT_NO_OPENSSL
+ else if (request().url() == QUrl("qrc:/fake-ssl-error.html"))
+ return;
+#endif
+
+ emit readyRead();
+ emit finished();
+ }
+};
+
+class FakeNetworkManager : public QNetworkAccessManager {
+ Q_OBJECT
+
+public:
+ FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { }
+
+protected:
+ virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
+ {
+ QString url = request.url().toString();
+ if (op == QNetworkAccessManager::GetOperation) {
+ if (url == "qrc:/test1.html" || url == "http://abcdef.abcdef/")
+ return new FakeReply(request, this);
+#ifndef QT_NO_OPENSSL
+ else if (url == "qrc:/fake-ssl-error.html") {
+ FakeReply* reply = new FakeReply(request, this);
+ QList<QSslError> errors;
+ emit sslErrors(reply, errors << QSslError(QSslError::UnspecifiedError));
+ return reply;
+ }
+#endif
+ }
+
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+ }
+};
+
+void tst_QWebFrame::requestedUrl()
+{
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+
+ // in few seconds, the image should be completely loaded
+ QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
+ FakeNetworkManager* networkManager = new FakeNetworkManager(&page);
+ page.setNetworkAccessManager(networkManager);
+
+ frame->setUrl(QUrl("qrc:/test1.html"));
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(frame->requestedUrl(), QUrl("qrc:/test1.html"));
+ QCOMPARE(frame->url(), QUrl("qrc:/test2.html"));
+
+ frame->setUrl(QUrl("qrc:/non-existent.html"));
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy.count(), 2);
+ QCOMPARE(frame->requestedUrl(), QUrl("qrc:/non-existent.html"));
+ QCOMPARE(frame->url(), QUrl("qrc:/non-existent.html"));
+
+ frame->setUrl(QUrl("http://abcdef.abcdef"));
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy.count(), 3);
+ QCOMPARE(frame->requestedUrl(), QUrl("http://abcdef.abcdef/"));
+ QCOMPARE(frame->url(), QUrl("http://abcdef.abcdef/"));
+
+#ifndef QT_NO_OPENSSL
+ qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
+ qRegisterMetaType<QNetworkReply* >("QNetworkReply*");
+
+ QSignalSpy spy2(page.networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
+ frame->setUrl(QUrl("qrc:/fake-ssl-error.html"));
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(frame->requestedUrl(), QUrl("qrc:/fake-ssl-error.html"));
+ QCOMPARE(frame->url(), QUrl("qrc:/fake-ssl-error.html"));
+#endif
+}
+
+void tst_QWebFrame::requestedUrlAfterSetAndLoadFailures()
+{
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+
+ QSignalSpy spy(frame, SIGNAL(loadFinished(bool)));
+
+ const QUrl first("http://abcdef.abcdef/");
+ frame->setUrl(first);
+ ::waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QCOMPARE(frame->url(), first);
+ QCOMPARE(frame->requestedUrl(), first);
+ QVERIFY(!spy.at(0).first().toBool());
+
+ const QUrl second("http://abcdef.abcdef/another_page.html");
+ QVERIFY(first != second);
+
+ frame->load(second);
+ ::waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QCOMPARE(frame->url(), first);
+ QCOMPARE(frame->requestedUrl(), second);
+ QVERIFY(!spy.at(1).first().toBool());
+}
+
+void tst_QWebFrame::javaScriptWindowObjectCleared_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::addColumn<int>("signalCount");
+ QTest::newRow("with <script>") << "<html><body><script>i=0</script><p>hello world</p></body></html>" << 1;
+ // NOTE: Empty scripts no longer cause this signal to be emitted.
+ QTest::newRow("with empty <script>") << "<html><body><script></script><p>hello world</p></body></html>" << 0;
+ QTest::newRow("without <script>") << "<html><body><p>hello world</p></body></html>" << 0;
+}
+
+void tst_QWebFrame::javaScriptWindowObjectCleared()
+{
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
+ QFETCH(QString, html);
+ frame->setHtml(html);
+
+ QFETCH(int, signalCount);
+ QCOMPARE(spy.count(), signalCount);
+}
+
+void tst_QWebFrame::javaScriptWindowObjectClearedOnEvaluate()
+{
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
+ frame->setHtml("<html></html>");
+ QCOMPARE(spy.count(), 0);
+ frame->evaluateJavaScript("var a = 'a';");
+ QCOMPARE(spy.count(), 1);
+ // no new clear for a new script:
+ frame->evaluateJavaScript("var a = 1;");
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QWebFrame::setHtml()
+{
+ QString html("<html><head></head><body><p>hello world</p></body></html>");
+ QSignalSpy spy(m_view->page(), SIGNAL(loadFinished(bool)));
+ m_view->page()->mainFrame()->setHtml(html);
+ QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QWebFrame::setHtmlWithResource()
+{
+ QString html("<html><body><p>hello world</p><img src='qrc:/image.png'/></body></html>");
+
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+
+ // in few seconds, the image should be completey loaded
+ QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
+ frame->setHtml(html);
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy.count(), 1);
+
+ QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
+ QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
+ QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
+
+ QString html2 =
+ "<html>"
+ "<head>"
+ "<link rel='stylesheet' href='qrc:/style.css' type='text/css' />"
+ "</head>"
+ "<body>"
+ "<p id='idP'>some text</p>"
+ "</body>"
+ "</html>";
+
+ // in few seconds, the CSS should be completey loaded
+ frame->setHtml(html2);
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy.size(), 2);
+
+ QWebElement p = frame->documentElement().findAll("p").at(0);
+ QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("red"));
+}
+
+void tst_QWebFrame::setHtmlWithBaseURL()
+{
+ if (!QDir(TESTS_SOURCE_DIR).exists())
+ QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
+
+ QDir::setCurrent(TESTS_SOURCE_DIR);
+
+ QString html("<html><body><p>hello world</p><img src='resources/image2.png'/></body></html>");
+
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+
+ // in few seconds, the image should be completey loaded
+ QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
+
+ frame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(spy.count(), 1);
+
+ QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
+ QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
+ QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
+
+ // no history item has to be added.
+ QCOMPARE(m_view->page()->history()->count(), 0);
+}
+
+class MyPage : public QWebPage
+{
+public:
+ MyPage() : QWebPage(), alerts(0) {}
+ int alerts;
+
+protected:
+ virtual void javaScriptAlert(QWebFrame*, const QString& msg)
+ {
+ alerts++;
+ QCOMPARE(msg, QString("foo"));
+ // Should not be enough to trigger deferred loading, since we've upped the HTML
+ // tokenizer delay in the Qt frameloader. See HTMLTokenizer::continueProcessing()
+ QTest::qWait(1000);
+ }
+};
+
+void tst_QWebFrame::setHtmlWithJSAlert()
+{
+ QString html("<html><head></head><body><script>alert('foo');</script><p>hello world</p></body></html>");
+ MyPage page;
+ m_view->setPage(&page);
+ page.mainFrame()->setHtml(html);
+ QCOMPARE(page.alerts, 1);
+ QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
+}
+
+class TestNetworkManager : public QNetworkAccessManager
+{
+public:
+ TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
+
+ QList<QUrl> requestedUrls;
+
+protected:
+ virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
+ requestedUrls.append(request.url());
+ QNetworkRequest redirectedRequest = request;
+ redirectedRequest.setUrl(QUrl("data:text/html,<p>hello"));
+ return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData);
+ }
+};
+
+void tst_QWebFrame::ipv6HostEncoding()
+{
+ TestNetworkManager* networkManager = new TestNetworkManager(m_page);
+ m_page->setNetworkAccessManager(networkManager);
+ networkManager->requestedUrls.clear();
+
+ QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html");
+ m_view->setHtml("<p>Hi", baseUrl);
+ m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();"
+ "r.open('GET', 'http://[::1]/test.xml', false);"
+ "r.send(null);"
+ );
+ QCOMPARE(networkManager->requestedUrls.count(), 1);
+ QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml"));
+}
+
+void tst_QWebFrame::metaData()
+{
+ m_view->setHtml("<html>"
+ " <head>"
+ " <meta name=\"description\" content=\"Test description\">"
+ " <meta name=\"keywords\" content=\"HTML, JavaScript, Css\">"
+ " </head>"
+ "</html>");
+
+ QMultiMap<QString, QString> metaData = m_view->page()->mainFrame()->metaData();
+
+ QCOMPARE(metaData.count(), 2);
+
+ QCOMPARE(metaData.value("description"), QString("Test description"));
+ QCOMPARE(metaData.value("keywords"), QString("HTML, JavaScript, Css"));
+ QCOMPARE(metaData.value("nonexistant"), QString());
+
+ m_view->setHtml("<html>"
+ " <head>"
+ " <meta name=\"samekey\" content=\"FirstValue\">"
+ " <meta name=\"samekey\" content=\"SecondValue\">"
+ " </head>"
+ "</html>");
+
+ metaData = m_view->page()->mainFrame()->metaData();
+
+ QCOMPARE(metaData.count(), 2);
+
+ QStringList values = metaData.values("samekey");
+ QCOMPARE(values.count(), 2);
+
+ QVERIFY(values.contains("FirstValue"));
+ QVERIFY(values.contains("SecondValue"));
+
+ QCOMPARE(metaData.value("nonexistant"), QString());
+}
+
+#if !defined(Q_WS_MAEMO_5) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_COMBOBOX)
+void tst_QWebFrame::popupFocus()
+{
+ QWebView view;
+ view.setHtml("<html>"
+ " <body>"
+ " <select name=\"select\">"
+ " <option>1</option>"
+ " <option>2</option>"
+ " </select>"
+ " <input type=\"text\"> </input>"
+ " <textarea name=\"text_area\" rows=\"3\" cols=\"40\">"
+ "This test checks whether showing and hiding a popup"
+ "takes the focus away from the webpage."
+ " </textarea>"
+ " </body>"
+ "</html>");
+ view.resize(400, 100);
+ // Call setFocus before show to work around http://bugreports.qt.nokia.com/browse/QTBUG-14762
+ view.setFocus();
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.activateWindow();
+ QTRY_VERIFY(view.hasFocus());
+
+ // open the popup by clicking. check if focus is on the popup
+ const QWebElement webCombo = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("select[name=select]"));
+ QTest::mouseClick(&view, Qt::LeftButton, 0, webCombo.geometry().center());
+ QObject* webpopup = firstChildByClassName(&view, "QComboBox");
+ QComboBox* combo = qobject_cast<QComboBox*>(webpopup);
+ QVERIFY(combo != 0);
+ QTRY_VERIFY(!view.hasFocus() && combo->view()->hasFocus()); // Focus should be on the popup
+
+ // hide the popup and check if focus is on the page
+ combo->hidePopup();
+ QTRY_VERIFY(view.hasFocus()); // Focus should be back on the WebView
+}
+#endif
+
+void tst_QWebFrame::inputFieldFocus()
+{
+ QWebView view;
+ view.setHtml("<html><body><input type=\"text\"></input></body></html>");
+ view.resize(400, 100);
+ view.show();
+ QTest::qWaitForWindowShown(&view);
+ view.activateWindow();
+ view.setFocus();
+ QTRY_VERIFY(view.hasFocus());
+
+ // double the flashing time, should at least blink once already
+ int delay = qApp->cursorFlashTime() * 2;
+
+ // focus the lineedit and check if it blinks
+ bool autoSipEnabled = qApp->autoSipEnabled();
+ qApp->setAutoSipEnabled(false);
+ const QWebElement inputElement = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("input[type=text]"));
+ QTest::mouseClick(&view, Qt::LeftButton, 0, inputElement.geometry().center());
+ m_inputFieldsTestView = &view;
+ view.installEventFilter( this );
+ QTest::qWait(delay);
+ QVERIFY2(m_inputFieldTestPaintCount >= 3,
+ "The input field should have a blinking caret");
+ qApp->setAutoSipEnabled(autoSipEnabled);
+}
+
+void tst_QWebFrame::hitTestContent()
+{
+ QString html("<html><body><p>A paragraph</p><br/><br/><br/><a href=\"about:blank\" target=\"_foo\" id=\"link\">link text</a></body></html>");
+
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ frame->setHtml(html);
+ page.setViewportSize(QSize(200, 0)); //no height so link is not visible
+ const QWebElement linkElement = frame->documentElement().findFirst(QLatin1String("a#link"));
+ QWebHitTestResult result = frame->hitTestContent(linkElement.geometry().center());
+ QCOMPARE(result.linkText(), QString("link text"));
+ QWebElement link = result.linkElement();
+ QCOMPARE(link.attribute("target"), QString("_foo"));
+}
+
+void tst_QWebFrame::jsByteArray()
+{
+ QByteArray ba("hello world");
+ m_myObject->setByteArrayProperty(ba);
+
+ // read-only property
+ QCOMPARE(m_myObject->byteArrayProperty(), ba);
+ QString type;
+ QVariant v = evalJSV("myObject.byteArrayProperty");
+ QCOMPARE(int(v.type()), int(QVariant::ByteArray));
+
+ QCOMPARE(v.toByteArray(), ba);
+}
+
+void tst_QWebFrame::ownership()
+{
+ // test ownership
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::ScriptOwnership);
+ }
+ QVERIFY(ptr == 0);
+ }
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ QObject* before = ptr;
+ {
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::QtOwnership);
+ }
+ QVERIFY(ptr == before);
+ delete ptr;
+ }
+ {
+ QObject* parent = new QObject();
+ QObject* child = new QObject(parent);
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ frame->addToJavaScriptWindowObject("test", child, QScriptEngine::QtOwnership);
+ QVariant v = frame->evaluateJavaScript("test");
+ QCOMPARE(qvariant_cast<QObject*>(v), child);
+ delete parent;
+ v = frame->evaluateJavaScript("test");
+ QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0);
+ }
+ {
+ QPointer<QObject> ptr = new QObject();
+ QVERIFY(ptr != 0);
+ {
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::AutoOwnership);
+ }
+ // no parent, so it should be like ScriptOwnership
+ QVERIFY(ptr == 0);
+ }
+ {
+ QObject* parent = new QObject();
+ QPointer<QObject> child = new QObject(parent);
+ QVERIFY(child != 0);
+ {
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ frame->addToJavaScriptWindowObject("test", child, QScriptEngine::AutoOwnership);
+ }
+ // has parent, so it should be like QtOwnership
+ QVERIFY(child != 0);
+ delete parent;
+ }
+}
+
+void tst_QWebFrame::nullValue()
+{
+ QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null");
+ QVERIFY(v.isNull());
+}
+
+void tst_QWebFrame::baseUrl_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::addColumn<QUrl>("loadUrl");
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QUrl>("baseUrl");
+
+ QTest::newRow("null") << QString() << QUrl()
+ << QUrl("about:blank") << QUrl("about:blank");
+
+ QTest::newRow("foo") << QString() << QUrl("http://foobar.baz/")
+ << QUrl("http://foobar.baz/") << QUrl("http://foobar.baz/");
+
+ QString html = "<html>"
+ "<head>"
+ "<base href=\"http://foobaz.bar/\" />"
+ "</head>"
+ "</html>";
+ QTest::newRow("customBaseUrl") << html << QUrl("http://foobar.baz/")
+ << QUrl("http://foobar.baz/") << QUrl("http://foobaz.bar/");
+}
+
+void tst_QWebFrame::baseUrl()
+{
+ QFETCH(QString, html);
+ QFETCH(QUrl, loadUrl);
+ QFETCH(QUrl, url);
+ QFETCH(QUrl, baseUrl);
+
+ m_page->mainFrame()->setHtml(html, loadUrl);
+ QCOMPARE(m_page->mainFrame()->url(), url);
+ QCOMPARE(m_page->mainFrame()->baseUrl(), baseUrl);
+}
+
+void tst_QWebFrame::hasSetFocus()
+{
+ QString html("<html><body><p>top</p>" \
+ "<iframe width='80%' height='30%'/>" \
+ "</body></html>");
+
+ QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
+ m_page->mainFrame()->setHtml(html);
+
+ waitForSignal(m_page->mainFrame(), SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(loadSpy.size(), 1);
+
+ QList<QWebFrame*> children = m_page->mainFrame()->childFrames();
+ QWebFrame* frame = children.at(0);
+ QString innerHtml("<html><body><p>another iframe</p>" \
+ "<iframe width='80%' height='30%'/>" \
+ "</body></html>");
+ frame->setHtml(innerHtml);
+
+ waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
+ QCOMPARE(loadSpy.size(), 2);
+
+ m_page->mainFrame()->setFocus();
+ QTRY_VERIFY(m_page->mainFrame()->hasFocus());
+
+ for (int i = 0; i < children.size(); ++i) {
+ children.at(i)->setFocus();
+ QTRY_VERIFY(children.at(i)->hasFocus());
+ QVERIFY(!m_page->mainFrame()->hasFocus());
+ }
+
+ m_page->mainFrame()->setFocus();
+ QTRY_VERIFY(m_page->mainFrame()->hasFocus());
+}
+
+void tst_QWebFrame::render()
+{
+ QString html("<html>" \
+ "<head><style>" \
+ "body, iframe { margin: 0px; border: none; }" \
+ "</style></head>" \
+ "<body><iframe width='100px' height='100px'/></body>" \
+ "</html>");
+
+ QWebPage page;
+ page.mainFrame()->setHtml(html);
+
+ QList<QWebFrame*> frames = page.mainFrame()->childFrames();
+ QWebFrame *frame = frames.at(0);
+ QString innerHtml("<body style='margin: 0px;'><img src='qrc:/image.png'/></body>");
+ frame->setHtml(innerHtml);
+
+ QPicture picture;
+
+ QSize size = page.mainFrame()->contentsSize();
+ page.setViewportSize(size);
+
+ // render contents layer only (the iframe is smaller than the image, so it will have scrollbars)
+ QPainter painter1(&picture);
+ frame->render(&painter1, QWebFrame::ContentsLayer);
+ painter1.end();
+
+ QCOMPARE(size.width(), picture.boundingRect().width() + frame->scrollBarGeometry(Qt::Vertical).width());
+ QCOMPARE(size.height(), picture.boundingRect().height() + frame->scrollBarGeometry(Qt::Horizontal).height());
+
+ // render everything, should be the size of the iframe
+ QPainter painter2(&picture);
+ frame->render(&painter2, QWebFrame::AllLayers);
+ painter2.end();
+
+ QCOMPARE(size.width(), picture.boundingRect().width()); // width: 100px
+ QCOMPARE(size.height(), picture.boundingRect().height()); // height: 100px
+}
+
+
+class DummyPaintEngine: public QPaintEngine {
+public:
+
+ DummyPaintEngine()
+ : QPaintEngine(QPaintEngine::AllFeatures)
+ , renderHints(0)
+ {
+ }
+
+ bool begin(QPaintDevice*)
+ {
+ setActive(true);
+ return true;
+ }
+
+ bool end()
+ {
+ setActive(false);
+ return false;
+ }
+
+ void updateState(const QPaintEngineState& state)
+ {
+ renderHints = state.renderHints();
+ }
+
+ void drawPath(const QPainterPath&) { }
+ void drawPixmap(const QRectF&, const QPixmap&, const QRectF&) { }
+
+ QPaintEngine::Type type() const
+ {
+ return static_cast<QPaintEngine::Type>(QPaintEngine::User + 2);
+ }
+
+ QPainter::RenderHints renderHints;
+};
+
+class DummyPaintDevice: public QPaintDevice {
+public:
+ DummyPaintDevice()
+ : QPaintDevice()
+ , m_engine(new DummyPaintEngine)
+ {
+ }
+
+ ~DummyPaintDevice()
+ {
+ delete m_engine;
+ }
+
+ QPaintEngine* paintEngine() const
+ {
+ return m_engine;
+ }
+
+ QPainter::RenderHints renderHints() const
+ {
+ return m_engine->renderHints;
+ }
+
+protected:
+ int metric(PaintDeviceMetric metric) const;
+
+private:
+ DummyPaintEngine* m_engine;
+ friend class DummyPaintEngine;
+};
+
+
+int DummyPaintDevice::metric(PaintDeviceMetric metric) const
+{
+ switch (metric) {
+ case PdmWidth:
+ return 400;
+ break;
+
+ case PdmHeight:
+ return 200;
+ break;
+
+ case PdmNumColors:
+ return INT_MAX;
+ break;
+
+ case PdmDepth:
+ return 32;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+void tst_QWebFrame::renderHints()
+{
+ QString html("<html><body><p>Hello, world!</p></body></html>");
+
+ QWebPage page;
+ page.mainFrame()->setHtml(html);
+ page.setViewportSize(page.mainFrame()->contentsSize());
+
+ // We will call frame->render and trap the paint engine state changes
+ // to ensure that GraphicsContext does not clobber the render hints.
+ DummyPaintDevice buffer;
+ QPainter painter(&buffer);
+
+ painter.setRenderHint(QPainter::TextAntialiasing, false);
+ page.mainFrame()->render(&painter);
+ QVERIFY(!(buffer.renderHints() & QPainter::TextAntialiasing));
+ QVERIFY(!(buffer.renderHints() & QPainter::SmoothPixmapTransform));
+ QVERIFY(!(buffer.renderHints() & QPainter::HighQualityAntialiasing));
+
+ painter.setRenderHint(QPainter::TextAntialiasing, true);
+ page.mainFrame()->render(&painter);
+ QVERIFY(buffer.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(!(buffer.renderHints() & QPainter::SmoothPixmapTransform));
+ QVERIFY(!(buffer.renderHints() & QPainter::HighQualityAntialiasing));
+
+ painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ page.mainFrame()->render(&painter);
+ QVERIFY(buffer.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(buffer.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(buffer.renderHints() & QPainter::HighQualityAntialiasing));
+
+ painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
+ page.mainFrame()->render(&painter);
+ QVERIFY(buffer.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(buffer.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(buffer.renderHints() & QPainter::HighQualityAntialiasing);
+}
+
+void tst_QWebFrame::scrollPosition()
+{
+ // enlarged image in a small viewport, to provoke the scrollbars to appear
+ QString html("<html><body><img src='qrc:/image.png' height=500 width=500/></body></html>");
+
+ QWebPage page;
+ page.setViewportSize(QSize(200, 200));
+
+ QWebFrame* frame = page.mainFrame();
+ frame->setHtml(html);
+ frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
+ frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
+
+ // try to set the scroll offset programmatically
+ frame->setScrollPosition(QPoint(23, 29));
+ QCOMPARE(frame->scrollPosition().x(), 23);
+ QCOMPARE(frame->scrollPosition().y(), 29);
+
+ int x = frame->evaluateJavaScript("window.scrollX").toInt();
+ int y = frame->evaluateJavaScript("window.scrollY").toInt();
+ QCOMPARE(x, 23);
+ QCOMPARE(y, 29);
+}
+
+void tst_QWebFrame::scrollToAnchor()
+{
+ QWebPage page;
+ page.setViewportSize(QSize(480, 800));
+ QWebFrame* frame = page.mainFrame();
+
+ QString html("<html><body><p style=\"margin-bottom: 1500px;\">Hello.</p>"
+ "<p><a id=\"foo\">This</a> is an anchor</p>"
+ "<p style=\"margin-bottom: 1500px;\"><a id=\"bar\">This</a> is another anchor</p>"
+ "</body></html>");
+ frame->setHtml(html);
+ frame->setScrollPosition(QPoint(0, 0));
+ QCOMPARE(frame->scrollPosition().x(), 0);
+ QCOMPARE(frame->scrollPosition().y(), 0);
+
+ QWebElement fooAnchor = frame->findFirstElement("a[id=foo]");
+
+ frame->scrollToAnchor("foo");
+ QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
+
+ frame->scrollToAnchor("bar");
+ frame->scrollToAnchor("foo");
+ QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
+
+ frame->scrollToAnchor("top");
+ QCOMPARE(frame->scrollPosition().y(), 0);
+
+ frame->scrollToAnchor("bar");
+ frame->scrollToAnchor("notexist");
+ QVERIFY(frame->scrollPosition().y() != 0);
+}
+
+
+void tst_QWebFrame::scrollbarsOff()
+{
+ QWebView view;
+ QWebFrame* mainFrame = view.page()->mainFrame();
+
+ mainFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
+ mainFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
+
+ QString html("<script>" \
+ " function checkScrollbar() {" \
+ " if (innerWidth === document.documentElement.offsetWidth)" \
+ " document.getElementById('span1').innerText = 'SUCCESS';" \
+ " else" \
+ " document.getElementById('span1').innerText = 'FAIL';" \
+ " }" \
+ "</script>" \
+ "<body>" \
+ " <div style='margin-top:1000px ; margin-left:1000px'>" \
+ " <a id='offscreen' href='a'>End</a>" \
+ " </div>" \
+ "<span id='span1'></span>" \
+ "</body>");
+
+
+ view.setHtml(html);
+ ::waitForSignal(&view, SIGNAL(loadFinished(bool)));
+
+ mainFrame->evaluateJavaScript("checkScrollbar();");
+ QCOMPARE(mainFrame->documentElement().findAll("span").at(0).toPlainText(), QString("SUCCESS"));
+}
+
+void tst_QWebFrame::horizontalScrollAfterBack()
+{
+ QWebView view;
+ QWebFrame* frame = view.page()->mainFrame();
+ QSignalSpy loadSpy(view.page(), SIGNAL(loadFinished(bool)));
+
+ view.page()->settings()->setMaximumPagesInCache(2);
+ frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
+ frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
+
+ view.load(QUrl("qrc:/testiframe2.html"));
+ view.resize(200, 200);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_VERIFY((frame->scrollBarGeometry(Qt::Horizontal)).height());
+
+ view.load(QUrl("qrc:/testiframe.html"));
+ QTRY_COMPARE(loadSpy.count(), 2);
+
+ view.page()->triggerAction(QWebPage::Back);
+ QTRY_COMPARE(loadSpy.count(), 3);
+ QTRY_VERIFY((frame->scrollBarGeometry(Qt::Horizontal)).height());
+}
+
+void tst_QWebFrame::evaluateWillCauseRepaint()
+{
+ QWebView view;
+ QString html("<html><body>top<div id=\"junk\" style=\"display: block;\">"
+ "junk</div>bottom</body></html>");
+ view.setHtml(html);
+ view.show();
+
+ QTest::qWaitForWindowShown(&view);
+ view.page()->mainFrame()->evaluateJavaScript(
+ "document.getElementById('junk').style.display = 'none';");
+
+ ::waitForSignal(view.page(), SIGNAL(repaintRequested(QRect)));
+}
+
+class TestFactory : public QObject
+{
+ Q_OBJECT
+public:
+ TestFactory()
+ : obj(0), counter(0)
+ {}
+
+ Q_INVOKABLE QObject* getNewObject()
+ {
+ delete obj;
+ obj = new QObject(this);
+ obj->setObjectName(QLatin1String("test") + QString::number(++counter));
+ return obj;
+
+ }
+
+ QObject* obj;
+ int counter;
+};
+
+void tst_QWebFrame::qObjectWrapperWithSameIdentity()
+{
+ m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>"
+ "<body><span id='span1'>test</span></body>");
+
+ QWebFrame* mainFrame = m_view->page()->mainFrame();
+ QCOMPARE(mainFrame->toPlainText(), QString("test"));
+
+ mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QScriptEngine::ScriptOwnership);
+
+ mainFrame->evaluateJavaScript("triggerBug();");
+ QCOMPARE(mainFrame->toPlainText(), QString("test1"));
+
+ mainFrame->evaluateJavaScript("triggerBug();");
+ QCOMPARE(mainFrame->toPlainText(), QString("test2"));
+}
+
+void tst_QWebFrame::introspectQtMethods_data()
+{
+ QTest::addColumn<QString>("objectExpression");
+ QTest::addColumn<QString>("methodName");
+ QTest::addColumn<QStringList>("expectedPropertyNames");
+
+ QTest::newRow("myObject.mySignal")
+ << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name");
+ QTest::newRow("myObject.mySlot")
+ << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name");
+ QTest::newRow("myObject.myInvokable")
+ << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name");
+ QTest::newRow("myObject.mySignal.connect")
+ << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name");
+ QTest::newRow("myObject.mySignal.disconnect")
+ << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name");
+}
+
+void tst_QWebFrame::introspectQtMethods()
+{
+ QFETCH(QString, objectExpression);
+ QFETCH(QString, methodName);
+ QFETCH(QStringList, expectedPropertyNames);
+
+ QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName);
+ QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames);
+
+ for (int i = 0; i < expectedPropertyNames.size(); ++i) {
+ QString name = expectedPropertyNames.at(i);
+ QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue);
+ evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name));
+ QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object"));
+ QCOMPARE(evalJS("descriptor.get"), sUndefined);
+ QCOMPARE(evalJS("descriptor.set"), sUndefined);
+ QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue);
+ QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse);
+ QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse);
+ }
+
+ QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty());
+}
+
+void tst_QWebFrame::setContent_data()
+{
+ QTest::addColumn<QString>("mimeType");
+ QTest::addColumn<QByteArray>("testContents");
+ QTest::addColumn<QString>("expected");
+
+ QString str = QString::fromUtf8("ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει");
+ QTest::newRow("UTF-8 plain text") << "text/plain; charset=utf-8" << str.toUtf8() << str;
+
+ QTextCodec *utf16 = QTextCodec::codecForName("UTF-16");
+ if (utf16)
+ QTest::newRow("UTF-16 plain text") << "text/plain; charset=utf-16" << utf16->fromUnicode(str) << str;
+
+ str = QString::fromUtf8("Une chaîne de caractères à sa façon.");
+ QTest::newRow("latin-1 plain text") << "text/plain; charset=iso-8859-1" << str.toLatin1() << str;
+
+
+}
+
+void tst_QWebFrame::setContent()
+{
+ QFETCH(QString, mimeType);
+ QFETCH(QByteArray, testContents);
+ QFETCH(QString, expected);
+ m_view->setContent(testContents, mimeType);
+ QWebFrame* mainFrame = m_view->page()->mainFrame();
+ QCOMPARE(expected , mainFrame->toPlainText());
+}
+
+class CacheNetworkAccessManager : public QNetworkAccessManager {
+public:
+ CacheNetworkAccessManager(QObject* parent = 0)
+ : QNetworkAccessManager(parent)
+ , m_lastCacheLoad(QNetworkRequest::PreferNetwork)
+ {
+ }
+
+ virtual QNetworkReply* createRequest(Operation, const QNetworkRequest& request, QIODevice*)
+ {
+ QVariant cacheLoad = request.attribute(QNetworkRequest::CacheLoadControlAttribute);
+ if (cacheLoad.isValid())
+ m_lastCacheLoad = static_cast<QNetworkRequest::CacheLoadControl>(cacheLoad.toUInt());
+ else
+ m_lastCacheLoad = QNetworkRequest::PreferNetwork; // default value
+ return new FakeReply(request, this);
+ }
+
+ QNetworkRequest::CacheLoadControl lastCacheLoad() const
+ {
+ return m_lastCacheLoad;
+ }
+
+private:
+ QNetworkRequest::CacheLoadControl m_lastCacheLoad;
+};
+
+void tst_QWebFrame::setCacheLoadControlAttribute()
+{
+ QWebPage page;
+ CacheNetworkAccessManager* manager = new CacheNetworkAccessManager(&page);
+ page.setNetworkAccessManager(manager);
+ QWebFrame* frame = page.mainFrame();
+
+ QNetworkRequest request(QUrl("http://abcdef.abcdef/"));
+
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
+ frame->load(request);
+ QCOMPARE(manager->lastCacheLoad(), QNetworkRequest::AlwaysCache);
+
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ frame->load(request);
+ QCOMPARE(manager->lastCacheLoad(), QNetworkRequest::PreferCache);
+
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
+ frame->load(request);
+ QCOMPARE(manager->lastCacheLoad(), QNetworkRequest::AlwaysNetwork);
+
+ request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
+ frame->load(request);
+ QCOMPARE(manager->lastCacheLoad(), QNetworkRequest::PreferNetwork);
+}
+
+void tst_QWebFrame::webElementSlotOnly()
+{
+ MyWebElementSlotOnlyObject object;
+ m_page->mainFrame()->setHtml("<html><head><body></body></html>");
+ m_page->mainFrame()->addToJavaScriptWindowObject("myWebElementSlotObject", &object);
+ evalJS("myWebElementSlotObject.doSomethingWithWebElement(document.body)");
+ QCOMPARE(evalJS("myWebElementSlotObject.tagName"), QString("BODY"));
+}
+
+void tst_QWebFrame::setUrlWithPendingLoads()
+{
+ QWebPage page;
+ page.mainFrame()->setHtml("<img src='dummy:'/>");
+ page.mainFrame()->setUrl(QUrl("about:blank"));
+}
+
+void tst_QWebFrame::setUrlWithFragment_data()
+{
+ QTest::addColumn<QUrl>("previousUrl");
+ QTest::newRow("empty") << QUrl();
+ QTest::newRow("same URL no fragment") << QUrl("qrc:/test1.html");
+ // See comments in setUrlSameUrl about using setUrl() with the same url().
+ QTest::newRow("same URL with same fragment") << QUrl("qrc:/test1.html#");
+ QTest::newRow("same URL with different fragment") << QUrl("qrc:/test1.html#anotherFragment");
+ QTest::newRow("another URL") << QUrl("qrc:/test2.html");
+}
+
+// Based on bug report https://bugs.webkit.org/show_bug.cgi?id=32723
+void tst_QWebFrame::setUrlWithFragment()
+{
+ QFETCH(QUrl, previousUrl);
+
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+
+ if (!previousUrl.isEmpty()) {
+ frame->load(previousUrl);
+ ::waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QCOMPARE(frame->url(), previousUrl);
+ }
+
+ QSignalSpy spy(frame, SIGNAL(loadFinished(bool)));
+ const QUrl url("qrc:/test1.html#");
+ QVERIFY(!url.fragment().isNull());
+
+ frame->setUrl(url);
+ ::waitForSignal(frame, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(!frame->toPlainText().isEmpty());
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(frame->url(), url);
+}
+
+void tst_QWebFrame::setUrlToEmpty()
+{
+ int expectedLoadFinishedCount = 0;
+ const QUrl aboutBlank("about:blank");
+ const QUrl url("qrc:/test2.html");
+
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ QCOMPARE(frame->url(), QUrl());
+ QCOMPARE(frame->requestedUrl(), QUrl());
+ QCOMPARE(frame->baseUrl(), QUrl());
+
+ QSignalSpy spy(frame, SIGNAL(loadFinished(bool)));
+
+ // Set existing url
+ frame->setUrl(url);
+ expectedLoadFinishedCount++;
+ ::waitForSignal(frame, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(frame->baseUrl(), url);
+
+ // Set empty url
+ frame->setUrl(QUrl());
+ expectedLoadFinishedCount++;
+
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), aboutBlank);
+ QCOMPARE(frame->requestedUrl(), QUrl());
+ QCOMPARE(frame->baseUrl(), aboutBlank);
+
+ // Set existing url
+ frame->setUrl(url);
+ expectedLoadFinishedCount++;
+ ::waitForSignal(frame, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(frame->baseUrl(), url);
+
+ // Load empty url
+ frame->load(QUrl());
+ expectedLoadFinishedCount++;
+
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), aboutBlank);
+ QCOMPARE(frame->requestedUrl(), QUrl());
+ QCOMPARE(frame->baseUrl(), aboutBlank);
+}
+
+void tst_QWebFrame::setUrlToInvalid()
+{
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+
+ const QUrl invalidUrl("http://strange;hostname/here");
+ QVERIFY(!invalidUrl.isEmpty());
+ QVERIFY(!invalidUrl.isValid());
+ QVERIFY(invalidUrl != QUrl());
+
+ frame->setUrl(invalidUrl);
+ QCOMPARE(frame->url(), invalidUrl);
+ QCOMPARE(frame->requestedUrl(), invalidUrl);
+ QCOMPARE(frame->baseUrl(), invalidUrl);
+
+ // QUrls equivalent to QUrl() will be treated as such.
+ const QUrl aboutBlank("about:blank");
+ const QUrl anotherInvalidUrl("1http://bugs.webkit.org");
+ QVERIFY(!anotherInvalidUrl.isEmpty()); // and they are not necessarily empty.
+ QVERIFY(!anotherInvalidUrl.isValid());
+ QCOMPARE(anotherInvalidUrl, QUrl());
+
+ frame->setUrl(anotherInvalidUrl);
+ QCOMPARE(frame->url(), aboutBlank);
+ QCOMPARE(frame->requestedUrl(), anotherInvalidUrl);
+ QCOMPARE(frame->baseUrl(), aboutBlank);
+}
+
+void tst_QWebFrame::setUrlHistory()
+{
+ const QUrl aboutBlank("about:blank");
+ QUrl url;
+ int expectedLoadFinishedCount = 0;
+ QWebFrame* frame = m_page->mainFrame();
+ QSignalSpy spy(frame, SIGNAL(loadFinished(bool)));
+
+ QCOMPARE(m_page->history()->count(), 0);
+
+ frame->setUrl(QUrl());
+ expectedLoadFinishedCount++;
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), aboutBlank);
+ QCOMPARE(frame->requestedUrl(), QUrl());
+ QCOMPARE(m_page->history()->count(), 0);
+
+ url = QUrl("http://non.existant/");
+ frame->setUrl(url);
+ ::waitForSignal(m_page, SIGNAL(loadFinished(bool)));
+ expectedLoadFinishedCount++;
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(m_page->history()->count(), 0);
+
+ url = QUrl("qrc:/test1.html");
+ frame->setUrl(url);
+ ::waitForSignal(m_page, SIGNAL(loadFinished(bool)));
+ expectedLoadFinishedCount++;
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(m_page->history()->count(), 1);
+
+ frame->setUrl(QUrl());
+ expectedLoadFinishedCount++;
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), aboutBlank);
+ QCOMPARE(frame->requestedUrl(), QUrl());
+ QCOMPARE(m_page->history()->count(), 1);
+
+ // Loading same page as current in history, so history count doesn't change.
+ url = QUrl("qrc:/test1.html");
+ frame->setUrl(url);
+ ::waitForSignal(m_page, SIGNAL(loadFinished(bool)));
+ expectedLoadFinishedCount++;
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(m_page->history()->count(), 1);
+
+ url = QUrl("qrc:/test2.html");
+ frame->setUrl(url);
+ ::waitForSignal(m_page, SIGNAL(loadFinished(bool)));
+ expectedLoadFinishedCount++;
+ QCOMPARE(spy.count(), expectedLoadFinishedCount);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(m_page->history()->count(), 2);
+}
+
+void tst_QWebFrame::setUrlSameUrl()
+{
+ const QUrl url1("qrc:/test1.html");
+ const QUrl url2("qrc:/test2.html");
+
+ QWebPage page;
+ QWebFrame* frame = page.mainFrame();
+ FakeNetworkManager* networkManager = new FakeNetworkManager(&page);
+ page.setNetworkAccessManager(networkManager);
+
+ QSignalSpy spy(frame, SIGNAL(loadFinished(bool)));
+
+ frame->setUrl(url1);
+ waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QVERIFY(frame->url() != url1); // Nota bene: our QNAM redirects url1 to url2
+ QCOMPARE(frame->url(), url2);
+ QCOMPARE(spy.count(), 1);
+
+ frame->setUrl(url1);
+ waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QVERIFY(frame->url() != url1);
+ QCOMPARE(frame->url(), url2);
+ QCOMPARE(spy.count(), 2);
+
+ // Now a case without redirect. The existing behavior we have for setUrl()
+ // is more like a "clear(); load()", so the page will be loaded again, even
+ // if urlToBeLoaded == url(). This test should be changed if we want to
+ // make setUrl() early return in this case.
+ frame->setUrl(url2);
+ waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QCOMPARE(frame->url(), url2);
+ QCOMPARE(spy.count(), 3);
+
+ frame->setUrl(url1);
+ waitForSignal(frame, SIGNAL(loadFinished(bool)));
+ QCOMPARE(frame->url(), url2);
+ QCOMPARE(spy.count(), 4);
+}
+
+static inline QUrl extractBaseUrl(const QUrl& url)
+{
+ return url.resolved(QUrl());
+}
+
+void tst_QWebFrame::setUrlThenLoads_data()
+{
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QUrl>("baseUrl");
+
+ QTest::newRow("resource file") << QUrl("qrc:/test1.html") << extractBaseUrl(QUrl("qrc:/test1.html"));
+ QTest::newRow("base specified in HTML") << QUrl("data:text/html,<head><base href=\"http://different.base/\"></head>") << QUrl("http://different.base/");
+}
+
+void tst_QWebFrame::setUrlThenLoads()
+{
+ QFETCH(QUrl, url);
+ QFETCH(QUrl, baseUrl);
+ QWebFrame* frame = m_page->mainFrame();
+ QSignalSpy urlChangedSpy(frame, SIGNAL(urlChanged(QUrl)));
+ QSignalSpy startedSpy(frame, SIGNAL(loadStarted()));
+ QSignalSpy finishedSpy(frame, SIGNAL(loadFinished(bool)));
+
+ frame->setUrl(url);
+ QCOMPARE(startedSpy.count(), 1);
+ ::waitForSignal(frame, SIGNAL(urlChanged(QUrl)));
+ QCOMPARE(urlChangedSpy.count(), 1);
+ QVERIFY(finishedSpy.at(0).first().toBool());
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), url);
+ QCOMPARE(frame->baseUrl(), baseUrl);
+
+ const QUrl urlToLoad1("qrc:/test2.html");
+ const QUrl urlToLoad2("qrc:/test1.html");
+
+ // Just after first load. URL didn't changed yet.
+ frame->load(urlToLoad1);
+ QCOMPARE(startedSpy.count(), 2);
+ QCOMPARE(frame->url(), url);
+ QCOMPARE(frame->requestedUrl(), urlToLoad1);
+ QCOMPARE(frame->baseUrl(), baseUrl);
+
+ // After first URL changed.
+ ::waitForSignal(frame, SIGNAL(urlChanged(QUrl)));
+ QCOMPARE(urlChangedSpy.count(), 2);
+ QVERIFY(finishedSpy.at(1).first().toBool());
+ QCOMPARE(frame->url(), urlToLoad1);
+ QCOMPARE(frame->requestedUrl(), urlToLoad1);
+ QCOMPARE(frame->baseUrl(), extractBaseUrl(urlToLoad1));
+
+ // Just after second load. URL didn't changed yet.
+ frame->load(urlToLoad2);
+ QCOMPARE(startedSpy.count(), 3);
+ QCOMPARE(frame->url(), urlToLoad1);
+ QCOMPARE(frame->requestedUrl(), urlToLoad2);
+ QCOMPARE(frame->baseUrl(), extractBaseUrl(urlToLoad1));
+
+ // After second URL changed.
+ ::waitForSignal(frame, SIGNAL(urlChanged(QUrl)));
+ QCOMPARE(urlChangedSpy.count(), 3);
+ QVERIFY(finishedSpy.at(2).first().toBool());
+ QCOMPARE(frame->url(), urlToLoad2);
+ QCOMPARE(frame->requestedUrl(), urlToLoad2);
+ QCOMPARE(frame->baseUrl(), extractBaseUrl(urlToLoad2));
+}
+
+QTEST_MAIN(tst_QWebFrame)
+#include "tst_qwebframe.moc"
diff --git a/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.qrc b/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.qrc
new file mode 100644
index 0000000..2a7d0b9
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebframe/tst_qwebframe.qrc
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/">
+<file alias="image.png">resources/image.png</file>
+<file alias="style.css">resources/style.css</file>
+<file alias="test1.html">resources/test1.html</file>
+<file alias="test2.html">resources/test2.html</file>
+<file alias="testiframe.html">resources/testiframe.html</file>
+<file alias="testiframe2.html">resources/testiframe2.html</file>
+</qresource>
+</RCC>
diff --git a/Source/WebKit/qt/tests/qwebhistory/qwebhistory.pro b/Source/WebKit/qt/tests/qwebhistory/qwebhistory.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/qwebhistory.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebhistory/resources/page1.html b/Source/WebKit/qt/tests/qwebhistory/resources/page1.html
new file mode 100644
index 0000000..82fa4af
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/resources/page1.html
@@ -0,0 +1 @@
+<title>page1</title><body><h1>page1</h1></body>
diff --git a/Source/WebKit/qt/tests/qwebhistory/resources/page2.html b/Source/WebKit/qt/tests/qwebhistory/resources/page2.html
new file mode 100644
index 0000000..5307bdc
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/resources/page2.html
@@ -0,0 +1 @@
+<title>page2</title><body><h1>page2</h1></body>
diff --git a/Source/WebKit/qt/tests/qwebhistory/resources/page3.html b/Source/WebKit/qt/tests/qwebhistory/resources/page3.html
new file mode 100644
index 0000000..4e5547c
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/resources/page3.html
@@ -0,0 +1 @@
+<title>page3</title><body><h1>page3</h1></body>
diff --git a/Source/WebKit/qt/tests/qwebhistory/resources/page4.html b/Source/WebKit/qt/tests/qwebhistory/resources/page4.html
new file mode 100644
index 0000000..3c57aed
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/resources/page4.html
@@ -0,0 +1 @@
+<title>page4</title><body><h1>page4</h1></body>
diff --git a/Source/WebKit/qt/tests/qwebhistory/resources/page5.html b/Source/WebKit/qt/tests/qwebhistory/resources/page5.html
new file mode 100644
index 0000000..8593552
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/resources/page5.html
@@ -0,0 +1 @@
+<title>page5</title><body><h1>page5</h1></body>
diff --git a/Source/WebKit/qt/tests/qwebhistory/resources/page6.html b/Source/WebKit/qt/tests/qwebhistory/resources/page6.html
new file mode 100644
index 0000000..c5bbc6f
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/resources/page6.html
@@ -0,0 +1 @@
+<title>page6</title><body><h1>page6</h1></body>
diff --git a/Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.cpp b/Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.cpp
new file mode 100644
index 0000000..783214c
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.cpp
@@ -0,0 +1,397 @@
+/*
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <QtTest/QtTest>
+#include <QAction>
+
+#include "qwebpage.h"
+#include "qwebview.h"
+#include "qwebframe.h"
+#include "qwebhistory.h"
+#include "qdebug.h"
+
+class tst_QWebHistory : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebHistory();
+ virtual ~tst_QWebHistory();
+
+protected :
+ void loadPage(int nr)
+ {
+ frame->load(QUrl("qrc:/resources/page" + QString::number(nr) + ".html"));
+ waitForLoadFinished.exec();
+ }
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void title();
+ void count();
+ void back();
+ void forward();
+ void itemAt();
+ void goToItem();
+ void items();
+ void serialize_1(); //QWebHistory countity
+ void serialize_2(); //QWebHistory index
+ void serialize_3(); //QWebHistoryItem
+ void saveAndRestore_crash_1();
+ void saveAndRestore_crash_2();
+ void saveAndRestore_crash_3();
+ void popPushState_data();
+ void popPushState();
+ void clear();
+
+
+private:
+ QWebPage* page;
+ QWebFrame* frame;
+ QWebHistory* hist;
+ QEventLoop waitForLoadFinished; //operation on history are asynchronous!
+ int histsize;
+};
+
+tst_QWebHistory::tst_QWebHistory()
+{
+}
+
+tst_QWebHistory::~tst_QWebHistory()
+{
+}
+
+void tst_QWebHistory::init()
+{
+ page = new QWebPage(this);
+ frame = page->mainFrame();
+ connect(page, SIGNAL(loadFinished(bool)), &waitForLoadFinished, SLOT(quit()), Qt::QueuedConnection);
+
+ for (int i = 1;i < 6;i++) {
+ loadPage(i);
+ }
+ hist = page->history();
+ histsize = 5;
+}
+
+void tst_QWebHistory::cleanup()
+{
+ delete page;
+}
+
+/**
+ * Check QWebHistoryItem::title() method
+ */
+void tst_QWebHistory::title()
+{
+ QCOMPARE(hist->currentItem().title(), QString("page5"));
+}
+
+/**
+ * Check QWebHistory::count() method
+ */
+void tst_QWebHistory::count()
+{
+ QCOMPARE(hist->count(), histsize);
+}
+
+/**
+ * Check QWebHistory::back() method
+ */
+void tst_QWebHistory::back()
+{
+ for (int i = histsize;i > 1;i--) {
+ QCOMPARE(page->mainFrame()->toPlainText(), QString("page") + QString::number(i));
+ hist->back();
+ waitForLoadFinished.exec();
+ }
+ //try one more time (too many). crash test
+ hist->back();
+ QCOMPARE(page->mainFrame()->toPlainText(), QString("page1"));
+}
+
+/**
+ * Check QWebHistory::forward() method
+ */
+void tst_QWebHistory::forward()
+{
+ //rewind history :-)
+ while (hist->canGoBack()) {
+ hist->back();
+ waitForLoadFinished.exec();
+ }
+
+ for (int i = 1;i < histsize;i++) {
+ QCOMPARE(page->mainFrame()->toPlainText(), QString("page") + QString::number(i));
+ hist->forward();
+ waitForLoadFinished.exec();
+ }
+ //try one more time (too many). crash test
+ hist->forward();
+ QCOMPARE(page->mainFrame()->toPlainText(), QString("page") + QString::number(histsize));
+}
+
+/**
+ * Check QWebHistory::itemAt() method
+ */
+void tst_QWebHistory::itemAt()
+{
+ for (int i = 1;i < histsize;i++) {
+ QCOMPARE(hist->itemAt(i - 1).title(), QString("page") + QString::number(i));
+ QVERIFY(hist->itemAt(i - 1).isValid());
+ }
+ //check out of range values
+ QVERIFY(!hist->itemAt(-1).isValid());
+ QVERIFY(!hist->itemAt(histsize).isValid());
+}
+
+/**
+ * Check QWebHistory::goToItem() method
+ */
+void tst_QWebHistory::goToItem()
+{
+ QWebHistoryItem current = hist->currentItem();
+ hist->back();
+ waitForLoadFinished.exec();
+ hist->back();
+ waitForLoadFinished.exec();
+ QVERIFY(hist->currentItem().title() != current.title());
+ hist->goToItem(current);
+ waitForLoadFinished.exec();
+ QCOMPARE(hist->currentItem().title(), current.title());
+}
+
+/**
+ * Check QWebHistory::items() method
+ */
+void tst_QWebHistory::items()
+{
+ QList<QWebHistoryItem> items = hist->items();
+ //check count
+ QCOMPARE(histsize, items.count());
+
+ //check order
+ for (int i = 1;i <= histsize;i++) {
+ QCOMPARE(items.at(i - 1).title(), QString("page") + QString::number(i));
+ }
+}
+
+/**
+ * Check history state after serialization (pickle, persistent..) method
+ * Checks history size, history order
+ */
+void tst_QWebHistory::serialize_1()
+{
+ QByteArray tmp; //buffer
+ QDataStream save(&tmp, QIODevice::WriteOnly); //here data will be saved
+ QDataStream load(&tmp, QIODevice::ReadOnly); //from here data will be loaded
+
+ save << *hist;
+ QVERIFY(save.status() == QDataStream::Ok);
+ QCOMPARE(hist->count(), histsize);
+
+ //check size of history
+ //load next page to find differences
+ loadPage(6);
+ QCOMPARE(hist->count(), histsize + 1);
+ load >> *hist;
+ QVERIFY(load.status() == QDataStream::Ok);
+ QCOMPARE(hist->count(), histsize);
+
+ //check order of historyItems
+ QList<QWebHistoryItem> items = hist->items();
+ for (int i = 1;i <= histsize;i++) {
+ QCOMPARE(items.at(i - 1).title(), QString("page") + QString::number(i));
+ }
+}
+
+/**
+ * Check history state after serialization (pickle, persistent..) method
+ * Checks history currentIndex value
+ */
+void tst_QWebHistory::serialize_2()
+{
+ QByteArray tmp; //buffer
+ QDataStream save(&tmp, QIODevice::WriteOnly); //here data will be saved
+ QDataStream load(&tmp, QIODevice::ReadOnly); //from here data will be loaded
+
+ int oldCurrentIndex = hist->currentItemIndex();
+
+ hist->back();
+ waitForLoadFinished.exec();
+ hist->back();
+ waitForLoadFinished.exec();
+ //check if current index was changed (make sure that it is not last item)
+ QVERIFY(hist->currentItemIndex() != oldCurrentIndex);
+ //save current index
+ oldCurrentIndex = hist->currentItemIndex();
+
+ save << *hist;
+ QVERIFY(save.status() == QDataStream::Ok);
+ load >> *hist;
+ QVERIFY(load.status() == QDataStream::Ok);
+
+ //check current index
+ QCOMPARE(hist->currentItemIndex(), oldCurrentIndex);
+}
+
+/**
+ * Check history state after serialization (pickle, persistent..) method
+ * Checks QWebHistoryItem public property after serialization
+ */
+void tst_QWebHistory::serialize_3()
+{
+ QByteArray tmp; //buffer
+ QDataStream save(&tmp, QIODevice::WriteOnly); //here data will be saved
+ QDataStream load(&tmp, QIODevice::ReadOnly); //from here data will be loaded
+
+ //prepare two different history items
+ QWebHistoryItem a = hist->currentItem();
+ a.setUserData("A - user data");
+
+ //check properties BEFORE serialization
+ QString title(a.title());
+ QDateTime lastVisited(a.lastVisited());
+ QUrl originalUrl(a.originalUrl());
+ QUrl url(a.url());
+ QVariant userData(a.userData());
+
+ save << *hist;
+ QVERIFY(save.status() == QDataStream::Ok);
+ QVERIFY(!load.atEnd());
+ hist->clear();
+ QVERIFY(hist->count() == 1);
+ load >> *hist;
+ QVERIFY(load.status() == QDataStream::Ok);
+ QWebHistoryItem b = hist->currentItem();
+
+ //check properties AFTER serialization
+ QCOMPARE(b.title(), title);
+ QCOMPARE(b.lastVisited(), lastVisited);
+ QCOMPARE(b.originalUrl(), originalUrl);
+ QCOMPARE(b.url(), url);
+ QCOMPARE(b.userData(), userData);
+
+ //Check if all data was read
+ QVERIFY(load.atEnd());
+}
+
+static void saveHistory(QWebHistory* history, QByteArray* in)
+{
+ in->clear();
+ QDataStream save(in, QIODevice::WriteOnly);
+ save << *history;
+}
+
+static void restoreHistory(QWebHistory* history, QByteArray* out)
+{
+ QDataStream load(out, QIODevice::ReadOnly);
+ load >> *history;
+}
+
+/** The test shouldn't crash */
+void tst_QWebHistory::saveAndRestore_crash_1()
+{
+ QByteArray buffer;
+ saveHistory(hist, &buffer);
+ for (unsigned i = 0; i < 5; i++) {
+ restoreHistory(hist, &buffer);
+ saveHistory(hist, &buffer);
+ }
+}
+
+/** The test shouldn't crash */
+void tst_QWebHistory::saveAndRestore_crash_2()
+{
+ QByteArray buffer;
+ saveHistory(hist, &buffer);
+ QWebPage* page2 = new QWebPage(this);
+ QWebHistory* hist2 = page2->history();
+ for (unsigned i = 0; i < 5; i++) {
+ restoreHistory(hist2, &buffer);
+ saveHistory(hist2, &buffer);
+ }
+ delete page2;
+}
+
+/** The test shouldn't crash */
+void tst_QWebHistory::saveAndRestore_crash_3()
+{
+ QByteArray buffer;
+ saveHistory(hist, &buffer);
+ QWebPage* page2 = new QWebPage(this);
+ QWebHistory* hist1 = hist;
+ QWebHistory* hist2 = page2->history();
+ for (unsigned i = 0; i < 5; i++) {
+ restoreHistory(hist1, &buffer);
+ restoreHistory(hist2, &buffer);
+ QVERIFY(hist1->count() == hist2->count());
+ QVERIFY(hist1->count() == histsize);
+ hist2->back();
+ saveHistory(hist2, &buffer);
+ hist2->clear();
+ }
+ delete page2;
+}
+
+void tst_QWebHistory::popPushState_data()
+{
+ QTest::addColumn<QString>("script");
+ QTest::newRow("pushState") << "history.pushState(123, \"foo\");";
+ QTest::newRow("replaceState") << "history.replaceState(\"a\", \"b\");";
+ QTest::newRow("back") << "history.back();";
+ QTest::newRow("forward") << "history.forward();";
+ QTest::newRow("clearState") << "history.clearState();";
+}
+
+/** Crash test, WebKit bug 38840 (https://bugs.webkit.org/show_bug.cgi?id=38840) */
+void tst_QWebHistory::popPushState()
+{
+ QFETCH(QString, script);
+ QWebPage page;
+ page.mainFrame()->setHtml("<html><body>long live Qt!</body></html>");
+ page.mainFrame()->evaluateJavaScript(script);
+}
+
+/** ::clear */
+void tst_QWebHistory::clear()
+{
+ QByteArray buffer;
+
+ QAction* actionBack = page->action(QWebPage::Back);
+ QVERIFY(actionBack->isEnabled());
+ saveHistory(hist, &buffer);
+ QVERIFY(hist->count() > 1);
+ hist->clear();
+ QVERIFY(hist->count() == 1); // Leave current item.
+ QVERIFY(!actionBack->isEnabled());
+
+ QWebPage* page2 = new QWebPage(this);
+ QWebHistory* hist2 = page2->history();
+ QVERIFY(hist2->count() == 0);
+ hist2->clear();
+ QVERIFY(hist2->count() == 0); // Do not change anything.
+ delete page2;
+}
+
+QTEST_MAIN(tst_QWebHistory)
+#include "tst_qwebhistory.moc"
diff --git a/Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.qrc b/Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.qrc
new file mode 100644
index 0000000..6e2f50a
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistory/tst_qwebhistory.qrc
@@ -0,0 +1,11 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/page1.html</file>
+ <file>resources/page2.html</file>
+ <file>resources/page3.html</file>
+ <file>resources/page4.html</file>
+ <file>resources/page5.html</file>
+ <file>resources/page6.html</file>
+</qresource>
+</RCC>
+
diff --git a/Source/WebKit/qt/tests/qwebhistoryinterface/qwebhistoryinterface.pro b/Source/WebKit/qt/tests/qwebhistoryinterface/qwebhistoryinterface.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistoryinterface/qwebhistoryinterface.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebhistoryinterface/tst_qwebhistoryinterface.cpp b/Source/WebKit/qt/tests/qwebhistoryinterface/tst_qwebhistoryinterface.cpp
new file mode 100644
index 0000000..84b12d2
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebhistoryinterface/tst_qwebhistoryinterface.cpp
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <QtTest/QtTest>
+
+#include <qwebpage.h>
+#include <qwebview.h>
+#include <qwebframe.h>
+#include <qwebelement.h>
+#include <qwebhistoryinterface.h>
+#include <QDebug>
+
+class tst_QWebHistoryInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebHistoryInterface();
+ virtual ~tst_QWebHistoryInterface();
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void visitedLinks();
+
+private:
+
+
+private:
+ QWebView* m_view;
+ QWebPage* m_page;
+};
+
+tst_QWebHistoryInterface::tst_QWebHistoryInterface()
+{
+}
+
+tst_QWebHistoryInterface::~tst_QWebHistoryInterface()
+{
+}
+
+void tst_QWebHistoryInterface::init()
+{
+ m_view = new QWebView();
+ m_page = m_view->page();
+}
+
+void tst_QWebHistoryInterface::cleanup()
+{
+ delete m_view;
+}
+
+class FakeHistoryImplementation : public QWebHistoryInterface {
+public:
+ void addHistoryEntry(const QString&) {}
+ bool historyContains(const QString& url) const {
+ return url == QLatin1String("http://www.trolltech.com/");
+ }
+};
+
+
+/*
+ * Test that visited links are properly colored. http://www.trolltech.com is marked
+ * as visited, so the below website should have exactly one element in the a:visited
+ * state.
+ */
+void tst_QWebHistoryInterface::visitedLinks()
+{
+ QWebHistoryInterface::setDefaultInterface(new FakeHistoryImplementation);
+ m_view->setHtml("<html><style>:link{color:green}:visited{color:red}</style><body><a href='http://www.trolltech.com' id='vlink'>Trolltech</a></body></html>");
+ QWebElement anchor = m_view->page()->mainFrame()->findFirstElement("a[id=vlink]");
+ QString linkColor = anchor.styleProperty("color", QWebElement::ComputedStyle);
+ QCOMPARE(linkColor, QString::fromLatin1("rgb(255, 0, 0)"));
+}
+
+QTEST_MAIN(tst_QWebHistoryInterface)
+#include "tst_qwebhistoryinterface.moc"
diff --git a/Source/WebKit/qt/tests/qwebinspector/qwebinspector.pro b/Source/WebKit/qt/tests/qwebinspector/qwebinspector.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebinspector/qwebinspector.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebinspector/tst_qwebinspector.cpp b/Source/WebKit/qt/tests/qwebinspector/tst_qwebinspector.cpp
new file mode 100644
index 0000000..12cd630
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebinspector/tst_qwebinspector.cpp
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <QtTest/QtTest>
+
+#include <qdir.h>
+#include <qwebinspector.h>
+#include <qwebpage.h>
+#include <qwebsettings.h>
+
+class tst_QWebInspector : public QObject {
+ Q_OBJECT
+
+private slots:
+ void attachAndDestroy();
+};
+
+void tst_QWebInspector::attachAndDestroy()
+{
+ { // External inspector + manual destruction of page first
+ QWebPage* page = new QWebPage();
+ page->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ QWebInspector* inspector = new QWebInspector();
+ inspector->setPage(page);
+ page->updatePositionDependentActions(QPoint(0, 0));
+ page->triggerAction(QWebPage::InspectElement);
+
+ delete page;
+ delete inspector;
+ }
+ { // External inspector + manual destruction of inspector first
+ QWebPage* page = new QWebPage();
+ page->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ QWebInspector* inspector = new QWebInspector();
+ inspector->setPage(page);
+ page->updatePositionDependentActions(QPoint(0, 0));
+ page->triggerAction(QWebPage::InspectElement);
+
+ delete inspector;
+ delete page;
+ }
+ { // Internal inspector
+ QWebPage page;
+ page.settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ page.updatePositionDependentActions(QPoint(0, 0));
+ page.triggerAction(QWebPage::InspectElement);
+ }
+}
+
+QTEST_MAIN(tst_QWebInspector)
+
+#include "tst_qwebinspector.moc"
diff --git a/Source/WebKit/qt/tests/qwebpage/qwebpage.pro b/Source/WebKit/qt/tests/qwebpage/qwebpage.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/qwebpage.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/content.html b/Source/WebKit/qt/tests/qwebpage/resources/content.html
new file mode 100644
index 0000000..823a983
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/content.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+<a>This is test content</a>
+</body>
+</html>
+
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/frame_a.html b/Source/WebKit/qt/tests/qwebpage/resources/frame_a.html
new file mode 100644
index 0000000..9ff68f1
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/frame_a.html
@@ -0,0 +1,2 @@
+<a href="http://google.com" target="frame_b"><img src="" width=100 height=100 alt="Google"></a>
+<a href="http://yahoo.com" target="frame_b"><img src="" width=100 height=100 alt="Yahoo"></a>
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/frame_c.html b/Source/WebKit/qt/tests/qwebpage/resources/frame_c.html
new file mode 100644
index 0000000..eba9ca0
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/frame_c.html
@@ -0,0 +1 @@
+<a href="content.html" target="frame_b"><img src="" width=100 height=100 alt="Google"></a>
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/framedindex.html b/Source/WebKit/qt/tests/qwebpage/resources/framedindex.html
new file mode 100644
index 0000000..465c6f0
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/framedindex.html
@@ -0,0 +1,4 @@
+<frameset cols="25%,75%">
+ <frame src="frame_c.html" name="frame_c">
+ <frame src="frame_b.html" name="frame_b">
+</frameset>
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/iframe.html b/Source/WebKit/qt/tests/qwebpage/resources/iframe.html
new file mode 100644
index 0000000..f17027c
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/iframe.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+<p>top</p>
+<iframe src="iframe2.html" width="80%" height="30%"/>
+</body>
+</html>
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/iframe2.html b/Source/WebKit/qt/tests/qwebpage/resources/iframe2.html
new file mode 100644
index 0000000..5017435
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/iframe2.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<p>another iframe</p>
+<iframe src="iframe3.html" width="80%" height="30%"></iframe>
+</body>
+</html>
+
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/iframe3.html b/Source/WebKit/qt/tests/qwebpage/resources/iframe3.html
new file mode 100644
index 0000000..ed6ac5b
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/iframe3.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<p>inner</p>
+</body>
+</html>
diff --git a/Source/WebKit/qt/tests/qwebpage/resources/index.html b/Source/WebKit/qt/tests/qwebpage/resources/index.html
new file mode 100644
index 0000000..c53ad09
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/resources/index.html
@@ -0,0 +1,4 @@
+<frameset cols="25%,75%">
+ <frame src="frame_a.html" name="frame_a">
+ <frame src="frame_b.html" name="frame_b">
+</frameset>
diff --git a/Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp b/Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp
new file mode 100644
index 0000000..9e3337b
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/tst_qwebpage.cpp
@@ -0,0 +1,2881 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ Copyright (C) 2010 Holger Hans Peter Freyther
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "../util.h"
+#include "../WebCoreSupport/DumpRenderTreeSupportQt.h"
+#include <QClipboard>
+#include <QDir>
+#include <QGraphicsWidget>
+#include <QLineEdit>
+#include <QMainWindow>
+#include <QMenu>
+#include <QPushButton>
+#include <QStyle>
+#include <QtTest/QtTest>
+#include <QTextCharFormat>
+#include <qgraphicsscene.h>
+#include <qgraphicsview.h>
+#include <qgraphicswebview.h>
+#include <qnetworkcookiejar.h>
+#include <qnetworkrequest.h>
+#include <qwebdatabase.h>
+#include <qwebelement.h>
+#include <qwebframe.h>
+#include <qwebhistory.h>
+#include <qwebpage.h>
+#include <qwebsecurityorigin.h>
+#include <qwebview.h>
+#include <qimagewriter.h>
+
+class EventSpy : public QObject, public QList<QEvent::Type>
+{
+ Q_OBJECT
+public:
+ EventSpy(QObject* objectToSpy)
+ {
+ objectToSpy->installEventFilter(this);
+ }
+
+ virtual bool eventFilter(QObject* receiver, QEvent* event)
+ {
+ append(event->type());
+ return false;
+ }
+};
+
+class tst_QWebPage : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebPage();
+ virtual ~tst_QWebPage();
+
+public slots:
+ void init();
+ void cleanup();
+ void cleanupFiles();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void contextMenuCopy();
+ void acceptNavigationRequest();
+ void geolocationRequestJS();
+ void loadFinished();
+ void acceptNavigationRequestWithNewWindow();
+ void userStyleSheet();
+ void loadHtml5Video();
+ void modified();
+ void contextMenuCrash();
+ void updatePositionDependentActionsCrash();
+ void database();
+ void createPluginWithPluginsEnabled();
+ void createPluginWithPluginsDisabled();
+ void destroyPlugin_data();
+ void destroyPlugin();
+ void createViewlessPlugin_data();
+ void createViewlessPlugin();
+ void graphicsWidgetPlugin();
+ void multiplePageGroupsAndLocalStorage();
+ void cursorMovements();
+ void textSelection();
+ void textEditing();
+ void backActionUpdate();
+ void frameAt();
+ void requestCache();
+ void loadCachedPage();
+ void protectBindingsRuntimeObjectsFromCollector();
+ void localURLSchemes();
+ void testOptionalJSObjects();
+ void testEnablePersistentStorage();
+ void consoleOutput();
+ void inputMethods_data();
+ void inputMethods();
+ void inputMethodsTextFormat_data();
+ void inputMethodsTextFormat();
+ void defaultTextEncoding();
+ void errorPageExtension();
+ void errorPageExtensionInIFrames();
+ void errorPageExtensionInFrameset();
+ void userAgentApplicationName();
+
+ void viewModes();
+
+ void crashTests_LazyInitializationOfMainFrame();
+
+ void screenshot_data();
+ void screenshot();
+
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+ void acceleratedWebGLScreenshotWithoutView();
+ void unacceleratedWebGLScreenshotWithoutView();
+#endif
+
+ void originatingObjectInNetworkRequests();
+ void testJSPrompt();
+ void showModalDialog();
+ void testStopScheduledPageRefresh();
+ void findText();
+ void supportedContentType();
+ void infiniteLoopJS();
+ void navigatorCookieEnabled();
+ void deleteQWebViewTwice();
+ void renderOnRepaintRequestedShouldNotRecurse();
+
+#ifdef Q_OS_MAC
+ void macCopyUnicodeToClipboard();
+#endif
+
+private:
+ QWebView* m_view;
+ QWebPage* m_page;
+};
+
+tst_QWebPage::tst_QWebPage()
+{
+}
+
+tst_QWebPage::~tst_QWebPage()
+{
+}
+
+void tst_QWebPage::init()
+{
+ m_view = new QWebView();
+ m_page = m_view->page();
+}
+
+void tst_QWebPage::cleanup()
+{
+ delete m_view;
+}
+
+void tst_QWebPage::cleanupFiles()
+{
+ QFile::remove("Databases.db");
+ QDir::current().rmdir("http_www.myexample.com_0");
+ QFile::remove("http_www.myexample.com_0.localstorage");
+}
+
+void tst_QWebPage::initTestCase()
+{
+ cleanupFiles(); // In case there are old files from previous runs
+}
+
+void tst_QWebPage::cleanupTestCase()
+{
+ cleanupFiles(); // Be nice
+}
+
+class NavigationRequestOverride : public QWebPage
+{
+public:
+ NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {}
+
+ bool m_acceptNavigationRequest;
+protected:
+ virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) {
+ Q_UNUSED(frame);
+ Q_UNUSED(request);
+ Q_UNUSED(type);
+
+ return m_acceptNavigationRequest;
+ }
+};
+
+void tst_QWebPage::acceptNavigationRequest()
+{
+ QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
+
+ NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false);
+ m_view->setPage(newPage);
+
+ m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
+ "<input type='text'><input type='submit'></form></body></html>"), QUrl());
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
+
+ newPage->m_acceptNavigationRequest = true;
+ m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
+ QTRY_COMPARE(loadSpy.count(), 2);
+
+ QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?"));
+
+ // Restore default page
+ m_view->setPage(0);
+}
+
+class JSTestPage : public QWebPage
+{
+Q_OBJECT
+public:
+ JSTestPage(QObject* parent = 0)
+ : QWebPage(parent) {}
+
+public slots:
+ bool shouldInterruptJavaScript() {
+ return true;
+ }
+ void requestPermission(QWebFrame* frame, QWebPage::Feature feature)
+ {
+ if (m_allowGeolocation)
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ else
+ setFeaturePermission(frame, feature, PermissionDeniedByUser);
+ }
+
+public:
+ void setGeolocationPermission(bool allow)
+ {
+ m_allowGeolocation = allow;
+ }
+
+private:
+ bool m_allowGeolocation;
+};
+
+void tst_QWebPage::infiniteLoopJS()
+{
+ JSTestPage* newPage = new JSTestPage(m_view);
+ m_view->setPage(newPage);
+ m_view->setHtml(QString("<html><body>test</body></html>"), QUrl());
+ m_view->page()->mainFrame()->evaluateJavaScript("var run = true;var a = 1;while(run){a++;}");
+ delete newPage;
+}
+
+void tst_QWebPage::geolocationRequestJS()
+{
+ JSTestPage* newPage = new JSTestPage(m_view);
+
+ if (newPage->mainFrame()->evaluateJavaScript(QLatin1String("!navigator.geolocation")).toBool()) {
+ delete newPage;
+ QSKIP("Geolocation is not supported.", SkipSingle);
+ }
+
+ connect(newPage, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)),
+ newPage, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
+
+ newPage->setGeolocationPermission(false);
+ m_view->setPage(newPage);
+ m_view->setHtml(QString("<html><body>test</body></html>"), QUrl());
+ m_view->page()->mainFrame()->evaluateJavaScript("var errorCode = 0; function error(err) { errorCode = err.code; } function success(pos) { } navigator.geolocation.getCurrentPosition(success, error)");
+ QTest::qWait(2000);
+ QVariant empty = m_view->page()->mainFrame()->evaluateJavaScript("errorCode");
+
+ QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 0);
+
+ newPage->setGeolocationPermission(true);
+ m_view->page()->mainFrame()->evaluateJavaScript("errorCode = 0; navigator.geolocation.getCurrentPosition(success, error);");
+ empty = m_view->page()->mainFrame()->evaluateJavaScript("errorCode");
+
+ //http://dev.w3.org/geo/api/spec-source.html#position
+ //PositionError: const unsigned short PERMISSION_DENIED = 1;
+ QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 1);
+ delete newPage;
+}
+
+void tst_QWebPage::loadFinished()
+{
+ qRegisterMetaType<QWebFrame*>("QWebFrame*");
+ qRegisterMetaType<QNetworkRequest*>("QNetworkRequest*");
+ QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted()));
+ QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
+
+ m_view->page()->mainFrame()->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
+ "<head><meta http-equiv='refresh' content='1'></head>foo \">"
+ "<frame src=\"data:text/html,bar\"></frameset>"));
+ QTRY_COMPARE(spyLoadFinished.count(), 1);
+
+ QTRY_VERIFY(spyLoadStarted.count() > 1);
+ QTRY_VERIFY(spyLoadFinished.count() > 1);
+
+ spyLoadFinished.clear();
+
+ m_view->page()->mainFrame()->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
+ "foo \"><frame src=\"data:text/html,bar\"></frameset>"));
+ QTRY_COMPARE(spyLoadFinished.count(), 1);
+ QCOMPARE(spyLoadFinished.count(), 1);
+}
+
+class ConsolePage : public QWebPage
+{
+public:
+ ConsolePage(QObject* parent = 0) : QWebPage(parent) {}
+
+ virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
+ {
+ messages.append(message);
+ lineNumbers.append(lineNumber);
+ sourceIDs.append(sourceID);
+ }
+
+ QStringList messages;
+ QList<int> lineNumbers;
+ QStringList sourceIDs;
+};
+
+void tst_QWebPage::consoleOutput()
+{
+ ConsolePage page;
+ page.mainFrame()->evaluateJavaScript("this is not valid JavaScript");
+ QCOMPARE(page.messages.count(), 1);
+ QCOMPARE(page.lineNumbers.at(0), 1);
+}
+
+class TestPage : public QWebPage
+{
+public:
+ TestPage(QObject* parent = 0) : QWebPage(parent) {}
+
+ struct Navigation {
+ QPointer<QWebFrame> frame;
+ QNetworkRequest request;
+ NavigationType type;
+ };
+
+ QList<Navigation> navigations;
+ QList<QWebPage*> createdWindows;
+
+ virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) {
+ Navigation n;
+ n.frame = frame;
+ n.request = request;
+ n.type = type;
+ navigations.append(n);
+ return true;
+ }
+
+ virtual QWebPage* createWindow(WebWindowType) {
+ QWebPage* page = new TestPage(this);
+ createdWindows.append(page);
+ return page;
+ }
+};
+
+void tst_QWebPage::acceptNavigationRequestWithNewWindow()
+{
+ TestPage* page = new TestPage(m_view);
+ page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
+ m_page = page;
+ m_view->setPage(m_page);
+
+ m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
+ QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
+
+ QFocusEvent fe(QEvent::FocusIn);
+ m_page->event(&fe);
+
+ QVERIFY(m_page->focusNextPrevChild(/*next*/ true));
+
+ QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
+ m_page->event(&keyEnter);
+
+ QCOMPARE(page->navigations.count(), 2);
+
+ TestPage::Navigation n = page->navigations.at(1);
+ QVERIFY(n.frame.isNull());
+ QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached"));
+ QVERIFY(n.type == QWebPage::NavigationTypeLinkClicked);
+
+ QCOMPARE(page->createdWindows.count(), 1);
+}
+
+class TestNetworkManager : public QNetworkAccessManager
+{
+public:
+ TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
+
+ QList<QUrl> requestedUrls;
+ QList<QNetworkRequest> requests;
+
+protected:
+ virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
+ requests.append(request);
+ requestedUrls.append(request.url());
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+ }
+};
+
+void tst_QWebPage::userStyleSheet()
+{
+ TestNetworkManager* networkManager = new TestNetworkManager(m_page);
+ m_page->setNetworkAccessManager(networkManager);
+ networkManager->requestedUrls.clear();
+
+ m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64,"
+ + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64()));
+ m_view->setHtml("<p>hello world</p>");
+ QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
+
+ QVERIFY(networkManager->requestedUrls.count() >= 1);
+ QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png"));
+}
+
+void tst_QWebPage::loadHtml5Video()
+{
+#if defined(WTF_USE_QT_MULTIMEDIA) && WTF_USE_QT_MULTIMEDIA
+ QByteArray url("http://does.not/exist?a=1%2Cb=2");
+ m_view->setHtml("<p><video id ='video' src='" + url + "' autoplay/></p>");
+ QTest::qWait(2000);
+ QUrl mUrl = DumpRenderTreeSupportQt::mediaContentUrlByElementId(m_page->mainFrame(), "video");
+ QCOMPARE(mUrl.toEncoded(), url);
+#else
+ QSKIP("This test requires Qt Multimedia", SkipAll);
+#endif
+}
+
+void tst_QWebPage::viewModes()
+{
+ m_view->setHtml("<body></body>");
+ m_page->setProperty("_q_viewMode", "minimized");
+
+ QVariant empty = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode)\")");
+ QVERIFY(empty.type() == QVariant::Bool && empty.toBool());
+
+ QVariant minimized = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode: minimized)\")");
+ QVERIFY(minimized.type() == QVariant::Bool && minimized.toBool());
+
+ QVariant maximized = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode: maximized)\")");
+ QVERIFY(maximized.type() == QVariant::Bool && !maximized.toBool());
+}
+
+void tst_QWebPage::modified()
+{
+ m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub"));
+ QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
+
+ m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah"));
+ QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
+
+ QVERIFY(!m_page->isModified());
+
+// m_page->mainFrame()->evaluateJavaScript("alert(document.getElementById('foo'))");
+ m_page->mainFrame()->evaluateJavaScript("document.getElementById('foo').focus()");
+ m_page->mainFrame()->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');");
+
+ QVERIFY(m_page->isModified());
+
+ m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);");
+
+ QVERIFY(!m_page->isModified());
+
+ m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);");
+
+ QVERIFY(m_page->isModified());
+
+ QVERIFY(m_page->history()->canGoBack());
+ QVERIFY(!m_page->history()->canGoForward());
+ QCOMPARE(m_page->history()->count(), 2);
+ QVERIFY(m_page->history()->backItem().isValid());
+ QVERIFY(!m_page->history()->forwardItem().isValid());
+
+ m_page->history()->back();
+ QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
+
+ QVERIFY(!m_page->history()->canGoBack());
+ QVERIFY(m_page->history()->canGoForward());
+
+ QVERIFY(!m_page->isModified());
+
+ QVERIFY(m_page->history()->currentItemIndex() == 0);
+
+ m_page->history()->setMaximumItemCount(3);
+ QVERIFY(m_page->history()->maximumItemCount() == 3);
+
+ QVariant variant("string test");
+ m_page->history()->currentItem().setUserData(variant);
+ QVERIFY(m_page->history()->currentItem().userData().toString() == "string test");
+
+ m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is second page"));
+ m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is third page"));
+ QVERIFY(m_page->history()->count() == 2);
+ m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fourth page"));
+ QVERIFY(m_page->history()->count() == 2);
+ m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fifth page"));
+ QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*))));
+}
+
+// https://bugs.webkit.org/show_bug.cgi?id=51331
+void tst_QWebPage::updatePositionDependentActionsCrash()
+{
+ QWebView view;
+ view.setHtml("<p>test");
+ QPoint pos(0, 0);
+ view.page()->updatePositionDependentActions(pos);
+ QMenu* contextMenu = 0;
+ foreach (QObject* child, view.children()) {
+ contextMenu = qobject_cast<QMenu*>(child);
+ if (contextMenu)
+ break;
+ }
+ QVERIFY(!contextMenu);
+}
+
+// https://bugs.webkit.org/show_bug.cgi?id=20357
+void tst_QWebPage::contextMenuCrash()
+{
+ QWebView view;
+ view.setHtml("<p>test");
+ QPoint pos(0, 0);
+ QContextMenuEvent event(QContextMenuEvent::Mouse, pos);
+ view.page()->swallowContextMenuEvent(&event);
+ view.page()->updatePositionDependentActions(pos);
+ QMenu* contextMenu = 0;
+ foreach (QObject* child, view.children()) {
+ contextMenu = qobject_cast<QMenu*>(child);
+ if (contextMenu)
+ break;
+ }
+ QVERIFY(contextMenu);
+ delete contextMenu;
+}
+
+void tst_QWebPage::database()
+{
+ QString path = QDir::currentPath();
+ m_page->settings()->setOfflineStoragePath(path);
+ QVERIFY(m_page->settings()->offlineStoragePath() == path);
+
+ QWebSettings::setOfflineStorageDefaultQuota(1024 * 1024);
+ QVERIFY(QWebSettings::offlineStorageDefaultQuota() == 1024 * 1024);
+
+ m_page->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
+ m_page->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
+
+ QString dbFileName = path + "Databases.db";
+
+ if (QFile::exists(dbFileName))
+ QFile::remove(dbFileName);
+
+ qRegisterMetaType<QWebFrame*>("QWebFrame*");
+ QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)));
+ m_view->setHtml(QString("<html><head><script>var db; db=openDatabase('testdb', '1.0', 'test database API', 50000); </script></head><body><div></div></body></html>"), QUrl("http://www.myexample.com"));
+ QTRY_COMPARE(spy.count(), 1);
+ m_page->mainFrame()->evaluateJavaScript("var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);");
+ QTRY_COMPARE(spy.count(),1);
+
+ m_page->mainFrame()->evaluateJavaScript("localStorage.test='This is a test for local storage';");
+ m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com"));
+
+ QVariant s1 = m_page->mainFrame()->evaluateJavaScript("localStorage.test");
+ QCOMPARE(s1.toString(), QString("This is a test for local storage"));
+
+ m_page->mainFrame()->evaluateJavaScript("sessionStorage.test='This is a test for session storage';");
+ m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com"));
+ QVariant s2 = m_page->mainFrame()->evaluateJavaScript("sessionStorage.test");
+ QCOMPARE(s2.toString(), QString("This is a test for session storage"));
+
+ m_view->setHtml(QString("<html><head></head><body><div></div></body></html>"), QUrl("http://www.myexample.com"));
+ m_page->mainFrame()->evaluateJavaScript("var db3; db3=openDatabase('testdb', '1.0', 'test database API', 50000);db3.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS Test (text TEXT)', []); }, function(tx, result) { }, function(tx, error) { });");
+ QTest::qWait(200);
+
+ // Remove all databases.
+ QWebSecurityOrigin origin = m_page->mainFrame()->securityOrigin();
+ QList<QWebDatabase> dbs = origin.databases();
+ for (int i = 0; i < dbs.count(); i++) {
+ QString fileName = dbs[i].fileName();
+ QVERIFY(QFile::exists(fileName));
+ QWebDatabase::removeDatabase(dbs[i]);
+ QVERIFY(!QFile::exists(fileName));
+ }
+ QVERIFY(!origin.databases().size());
+ // Remove removed test :-)
+ QWebDatabase::removeAllDatabases();
+ QVERIFY(!origin.databases().size());
+}
+
+class PluginPage : public QWebPage
+{
+public:
+ PluginPage(QObject *parent = 0)
+ : QWebPage(parent) {}
+
+ struct CallInfo
+ {
+ CallInfo(const QString &c, const QUrl &u,
+ const QStringList &pn, const QStringList &pv,
+ QObject *r)
+ : classid(c), url(u), paramNames(pn),
+ paramValues(pv), returnValue(r)
+ {}
+ QString classid;
+ QUrl url;
+ QStringList paramNames;
+ QStringList paramValues;
+ QObject *returnValue;
+ };
+
+ QList<CallInfo> calls;
+
+protected:
+ virtual QObject *createPlugin(const QString &classid, const QUrl &url,
+ const QStringList &paramNames,
+ const QStringList &paramValues)
+ {
+ QObject *result = 0;
+ if (classid == "pushbutton")
+ result = new QPushButton();
+#ifndef QT_NO_INPUTDIALOG
+ else if (classid == "lineedit")
+ result = new QLineEdit();
+#endif
+ else if (classid == "graphicswidget")
+ result = new QGraphicsWidget();
+ if (result)
+ result->setObjectName(classid);
+ calls.append(CallInfo(classid, url, paramNames, paramValues, result));
+ return result;
+ }
+};
+
+static void createPlugin(QWebView *view)
+{
+ QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool)));
+
+ PluginPage* newPage = new PluginPage(view);
+ view->setPage(newPage);
+
+ // type has to be application/x-qt-plugin
+ view->setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='pushbutton' id='mybutton'/></body></html>"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(newPage->calls.count(), 0);
+
+ view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>"));
+ QTRY_COMPARE(loadSpy.count(), 2);
+ QCOMPARE(newPage->calls.count(), 1);
+ {
+ PluginPage::CallInfo ci = newPage->calls.takeFirst();
+ QCOMPARE(ci.classid, QString::fromLatin1("pushbutton"));
+ QCOMPARE(ci.url, QUrl());
+ QCOMPARE(ci.paramNames.count(), 3);
+ QCOMPARE(ci.paramValues.count(), 3);
+ QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
+ QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
+ QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
+ QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton"));
+ QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
+ QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton"));
+ QVERIFY(ci.returnValue != 0);
+ QVERIFY(ci.returnValue->inherits("QPushButton"));
+ }
+ // test JS bindings
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("document.getElementById('mybutton').toString()").toString(),
+ QString::fromLatin1("[object HTMLObjectElement]"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.toString()").toString(),
+ QString::fromLatin1("[object HTMLObjectElement]"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.objectName").toString(),
+ QString::fromLatin1("string"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.objectName").toString(),
+ QString::fromLatin1("pushbutton"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.clicked").toString(),
+ QString::fromLatin1("function"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.clicked.toString()").toString(),
+ QString::fromLatin1("function clicked() {\n [native code]\n}"));
+
+ view->setHtml(QString("<html><body><table>"
+ "<tr><object type='application/x-qt-plugin' classid='lineedit' id='myedit'/></tr>"
+ "<tr><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></tr>"
+ "</table></body></html>"), QUrl("http://foo.bar.baz"));
+ QTRY_COMPARE(loadSpy.count(), 3);
+ QCOMPARE(newPage->calls.count(), 2);
+ {
+ PluginPage::CallInfo ci = newPage->calls.takeFirst();
+ QCOMPARE(ci.classid, QString::fromLatin1("lineedit"));
+ QCOMPARE(ci.url, QUrl());
+ QCOMPARE(ci.paramNames.count(), 3);
+ QCOMPARE(ci.paramValues.count(), 3);
+ QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
+ QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
+ QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
+ QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit"));
+ QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
+ QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit"));
+ QVERIFY(ci.returnValue != 0);
+ QVERIFY(ci.returnValue->inherits("QLineEdit"));
+ }
+ {
+ PluginPage::CallInfo ci = newPage->calls.takeFirst();
+ QCOMPARE(ci.classid, QString::fromLatin1("pushbutton"));
+ QCOMPARE(ci.url, QUrl());
+ QCOMPARE(ci.paramNames.count(), 3);
+ QCOMPARE(ci.paramValues.count(), 3);
+ QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
+ QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
+ QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
+ QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton"));
+ QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
+ QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton"));
+ QVERIFY(ci.returnValue != 0);
+ QVERIFY(ci.returnValue->inherits("QPushButton"));
+ }
+}
+
+void tst_QWebPage::graphicsWidgetPlugin()
+{
+ m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ QGraphicsWebView webView;
+
+ QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
+
+ PluginPage* newPage = new PluginPage(&webView);
+ webView.setPage(newPage);
+
+ // type has to be application/x-qt-plugin
+ webView.setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='graphicswidget' id='mygraphicswidget'/></body></html>"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QCOMPARE(newPage->calls.count(), 0);
+
+ webView.setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='graphicswidget' id='mygraphicswidget'/></body></html>"));
+ QTRY_COMPARE(loadSpy.count(), 2);
+ QCOMPARE(newPage->calls.count(), 1);
+ {
+ PluginPage::CallInfo ci = newPage->calls.takeFirst();
+ QCOMPARE(ci.classid, QString::fromLatin1("graphicswidget"));
+ QCOMPARE(ci.url, QUrl());
+ QCOMPARE(ci.paramNames.count(), 3);
+ QCOMPARE(ci.paramValues.count(), 3);
+ QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
+ QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
+ QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
+ QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("graphicswidget"));
+ QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
+ QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mygraphicswidget"));
+ QVERIFY(ci.returnValue);
+ QVERIFY(ci.returnValue->inherits("QGraphicsWidget"));
+ }
+ // test JS bindings
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("document.getElementById('mygraphicswidget').toString()").toString(),
+ QString::fromLatin1("[object HTMLObjectElement]"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mygraphicswidget.toString()").toString(),
+ QString::fromLatin1("[object HTMLObjectElement]"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mygraphicswidget.objectName").toString(),
+ QString::fromLatin1("string"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mygraphicswidget.objectName").toString(),
+ QString::fromLatin1("graphicswidget"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mygraphicswidget.geometryChanged").toString(),
+ QString::fromLatin1("function"));
+ QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mygraphicswidget.geometryChanged.toString()").toString(),
+ QString::fromLatin1("function geometryChanged() {\n [native code]\n}"));
+}
+
+void tst_QWebPage::createPluginWithPluginsEnabled()
+{
+ m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ createPlugin(m_view);
+}
+
+void tst_QWebPage::createPluginWithPluginsDisabled()
+{
+ // Qt Plugins should be loaded by QtWebKit even when PluginsEnabled is
+ // false. The client decides whether a Qt plugin is enabled or not when
+ // it decides whether or not to instantiate it.
+ m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, false);
+ createPlugin(m_view);
+}
+
+// Standard base class for template PluginTracerPage. In tests it is used as interface.
+class PluginCounterPage : public QWebPage {
+public:
+ int m_count;
+ QPointer<QObject> m_widget;
+ QObject* m_pluginParent;
+ PluginCounterPage(QObject* parent = 0)
+ : QWebPage(parent)
+ , m_count(0)
+ , m_widget(0)
+ , m_pluginParent(0)
+ {
+ settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ }
+ ~PluginCounterPage()
+ {
+ if (m_pluginParent)
+ m_pluginParent->deleteLater();
+ }
+};
+
+template<class T>
+class PluginTracerPage : public PluginCounterPage {
+public:
+ PluginTracerPage(QObject* parent = 0)
+ : PluginCounterPage(parent)
+ {
+ // this is a dummy parent object for the created plugin
+ m_pluginParent = new T;
+ }
+ virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&)
+ {
+ m_count++;
+ m_widget = new T;
+ // need a cast to the specific type, as QObject::setParent cannot be called,
+ // because it is not virtual. Instead it is necesary to call QWidget::setParent,
+ // which also takes a QWidget* instead of a QObject*. Therefore we need to
+ // upcast to T*, which is a QWidget.
+ static_cast<T*>(m_widget.data())->setParent(static_cast<T*>(m_pluginParent));
+ return m_widget;
+ }
+};
+
+class PluginFactory {
+public:
+ enum FactoredType {QWidgetType, QGraphicsWidgetType};
+ static PluginCounterPage* create(FactoredType type, QObject* parent = 0)
+ {
+ PluginCounterPage* result = 0;
+ switch (type) {
+ case QWidgetType:
+ result = new PluginTracerPage<QWidget>(parent);
+ break;
+ case QGraphicsWidgetType:
+ result = new PluginTracerPage<QGraphicsWidget>(parent);
+ break;
+ default: {/*Oops*/};
+ }
+ return result;
+ }
+
+ static void prepareTestData()
+ {
+ QTest::addColumn<int>("type");
+ QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType;
+ QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType;
+ }
+};
+
+void tst_QWebPage::destroyPlugin_data()
+{
+ PluginFactory::prepareTestData();
+}
+
+void tst_QWebPage::destroyPlugin()
+{
+ QFETCH(int, type);
+ PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view);
+ m_view->setPage(page);
+
+ // we create the plugin, so the widget should be constructed
+ QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>");
+ m_view->setHtml(content);
+ QVERIFY(page->m_widget);
+ QCOMPARE(page->m_count, 1);
+
+ // navigate away, the plugin widget should be destructed
+ m_view->setHtml("<html><body>Hi</body></html>");
+ QTestEventLoop::instance().enterLoop(1);
+ QVERIFY(!page->m_widget);
+}
+
+void tst_QWebPage::createViewlessPlugin_data()
+{
+ PluginFactory::prepareTestData();
+}
+
+void tst_QWebPage::createViewlessPlugin()
+{
+ QFETCH(int, type);
+ PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type);
+ QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>");
+ page->mainFrame()->setHtml(content);
+ QCOMPARE(page->m_count, 1);
+ QVERIFY(page->m_widget);
+ QVERIFY(page->m_pluginParent);
+ QVERIFY(page->m_widget->parent() == page->m_pluginParent);
+ delete page;
+
+}
+
+void tst_QWebPage::multiplePageGroupsAndLocalStorage()
+{
+ QDir dir(QDir::currentPath());
+ dir.mkdir("path1");
+ dir.mkdir("path2");
+
+ QWebView view1;
+ QWebView view2;
+
+ view1.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
+ view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path1"));
+ DumpRenderTreeSupportQt::webPageSetGroupName(view1.page(), "group1");
+ view2.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
+ view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path2"));
+ DumpRenderTreeSupportQt::webPageSetGroupName(view2.page(), "group2");
+ QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view1.page()), QString("group1"));
+ QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view2.page()), QString("group2"));
+
+
+ view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
+ view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
+
+ view1.page()->mainFrame()->evaluateJavaScript("localStorage.test='value1';");
+ view2.page()->mainFrame()->evaluateJavaScript("localStorage.test='value2';");
+
+ view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
+ view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
+
+ QVariant s1 = view1.page()->mainFrame()->evaluateJavaScript("localStorage.test");
+ QCOMPARE(s1.toString(), QString("value1"));
+
+ QVariant s2 = view2.page()->mainFrame()->evaluateJavaScript("localStorage.test");
+ QCOMPARE(s2.toString(), QString("value2"));
+
+ QTest::qWait(1000);
+
+ QFile::remove(QDir::toNativeSeparators(QDir::currentPath() + "/path1/http_www.myexample.com_0.localstorage"));
+ QFile::remove(QDir::toNativeSeparators(QDir::currentPath() + "/path2/http_www.myexample.com_0.localstorage"));
+ dir.rmdir(QDir::toNativeSeparators("./path1"));
+ dir.rmdir(QDir::toNativeSeparators("./path2"));
+}
+
+class CursorTrackedPage : public QWebPage
+{
+public:
+
+ CursorTrackedPage(QWidget *parent = 0): QWebPage(parent) {
+ setViewportSize(QSize(1024, 768)); // big space
+ }
+
+ QString selectedText() {
+ return mainFrame()->evaluateJavaScript("window.getSelection().toString()").toString();
+ }
+
+ int selectionStartOffset() {
+ return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).startOffset").toInt();
+ }
+
+ int selectionEndOffset() {
+ return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).endOffset").toInt();
+ }
+
+ // true if start offset == end offset, i.e. no selected text
+ int isSelectionCollapsed() {
+ return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).collapsed").toBool();
+ }
+};
+
+void tst_QWebPage::cursorMovements()
+{
+ CursorTrackedPage* page = new CursorTrackedPage;
+ QString content("<html><body><p id=one>The quick brown fox</p><p id=two>jumps over the lazy dog</p><p>May the source<br/>be with you!</p></body></html>");
+ page->mainFrame()->setHtml(content);
+
+ // this will select the first paragraph
+ QString script = "var range = document.createRange(); " \
+ "var node = document.getElementById(\"one\"); " \
+ "range.selectNode(node); " \
+ "getSelection().addRange(range);";
+ page->mainFrame()->evaluateJavaScript(script);
+ QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox"));
+
+ QRegExp regExp(" style=\".*\"");
+ regExp.setMinimal(true);
+ QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("<span class=\"Apple-style-span\"><p id=\"one\">The quick brown fox</p></span>"));
+
+ // these actions must exist
+ QVERIFY(page->action(QWebPage::MoveToNextChar) != 0);
+ QVERIFY(page->action(QWebPage::MoveToPreviousChar) != 0);
+ QVERIFY(page->action(QWebPage::MoveToNextWord) != 0);
+ QVERIFY(page->action(QWebPage::MoveToPreviousWord) != 0);
+ QVERIFY(page->action(QWebPage::MoveToNextLine) != 0);
+ QVERIFY(page->action(QWebPage::MoveToPreviousLine) != 0);
+ QVERIFY(page->action(QWebPage::MoveToStartOfLine) != 0);
+ QVERIFY(page->action(QWebPage::MoveToEndOfLine) != 0);
+ QVERIFY(page->action(QWebPage::MoveToStartOfBlock) != 0);
+ QVERIFY(page->action(QWebPage::MoveToEndOfBlock) != 0);
+ QVERIFY(page->action(QWebPage::MoveToStartOfDocument) != 0);
+ QVERIFY(page->action(QWebPage::MoveToEndOfDocument) != 0);
+
+ // right now they are disabled because contentEditable is false
+ QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), false);
+
+ // make it editable before navigating the cursor
+ page->setContentEditable(true);
+
+ // here the actions are enabled after contentEditable is true
+ QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), true);
+
+ // cursor will be before the word "jump"
+ page->triggerAction(QWebPage::MoveToNextChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // cursor will be between 'j' and 'u' in the word "jump"
+ page->triggerAction(QWebPage::MoveToNextChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 1);
+
+ // cursor will be between 'u' and 'm' in the word "jump"
+ page->triggerAction(QWebPage::MoveToNextChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 2);
+
+ // cursor will be after the word "jump"
+ page->triggerAction(QWebPage::MoveToNextWord);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 5);
+
+ // cursor will be after the word "lazy"
+ page->triggerAction(QWebPage::MoveToNextWord);
+ page->triggerAction(QWebPage::MoveToNextWord);
+ page->triggerAction(QWebPage::MoveToNextWord);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 19);
+
+ // cursor will be between 'z' and 'y' in "lazy"
+ page->triggerAction(QWebPage::MoveToPreviousChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 18);
+
+ // cursor will be between 'a' and 'z' in "lazy"
+ page->triggerAction(QWebPage::MoveToPreviousChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 17);
+
+ // cursor will be before the word "lazy"
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 15);
+
+ // cursor will be before the word "quick"
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 4);
+
+ // cursor will be between 'p' and 's' in the word "jumps"
+ page->triggerAction(QWebPage::MoveToNextWord);
+ page->triggerAction(QWebPage::MoveToNextWord);
+ page->triggerAction(QWebPage::MoveToNextWord);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 4);
+
+ // cursor will be before the word "jumps"
+ page->triggerAction(QWebPage::MoveToStartOfLine);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // cursor will be after the word "dog"
+ page->triggerAction(QWebPage::MoveToEndOfLine);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 23);
+
+ // cursor will be between 'w' and 'n' in "brown"
+ page->triggerAction(QWebPage::MoveToStartOfLine);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 14);
+
+ // cursor will be after the word "fox"
+ page->triggerAction(QWebPage::MoveToEndOfLine);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 19);
+
+ // cursor will be before the word "The"
+ page->triggerAction(QWebPage::MoveToStartOfDocument);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // cursor will be after the word "you!"
+ page->triggerAction(QWebPage::MoveToEndOfDocument);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 12);
+
+ // cursor will be before the word "be"
+ page->triggerAction(QWebPage::MoveToStartOfBlock);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // cursor will be after the word "you!"
+ page->triggerAction(QWebPage::MoveToEndOfBlock);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 12);
+
+ // try to move before the document start
+ page->triggerAction(QWebPage::MoveToStartOfDocument);
+ page->triggerAction(QWebPage::MoveToPreviousChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+ page->triggerAction(QWebPage::MoveToStartOfDocument);
+ page->triggerAction(QWebPage::MoveToPreviousWord);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // try to move past the document end
+ page->triggerAction(QWebPage::MoveToEndOfDocument);
+ page->triggerAction(QWebPage::MoveToNextChar);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 12);
+ page->triggerAction(QWebPage::MoveToEndOfDocument);
+ page->triggerAction(QWebPage::MoveToNextWord);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 12);
+
+ delete page;
+}
+
+void tst_QWebPage::textSelection()
+{
+ CursorTrackedPage* page = new CursorTrackedPage;
+ QString content("<html><body><p id=one>The quick brown fox</p>" \
+ "<p id=two>jumps over the lazy dog</p>" \
+ "<p>May the source<br/>be with you!</p></body></html>");
+ page->mainFrame()->setHtml(content);
+
+ // these actions must exist
+ QVERIFY(page->action(QWebPage::SelectAll) != 0);
+ QVERIFY(page->action(QWebPage::SelectNextChar) != 0);
+ QVERIFY(page->action(QWebPage::SelectPreviousChar) != 0);
+ QVERIFY(page->action(QWebPage::SelectNextWord) != 0);
+ QVERIFY(page->action(QWebPage::SelectPreviousWord) != 0);
+ QVERIFY(page->action(QWebPage::SelectNextLine) != 0);
+ QVERIFY(page->action(QWebPage::SelectPreviousLine) != 0);
+ QVERIFY(page->action(QWebPage::SelectStartOfLine) != 0);
+ QVERIFY(page->action(QWebPage::SelectEndOfLine) != 0);
+ QVERIFY(page->action(QWebPage::SelectStartOfBlock) != 0);
+ QVERIFY(page->action(QWebPage::SelectEndOfBlock) != 0);
+ QVERIFY(page->action(QWebPage::SelectStartOfDocument) != 0);
+ QVERIFY(page->action(QWebPage::SelectEndOfDocument) != 0);
+
+ // right now they are disabled because contentEditable is false and
+ // there isn't an existing selection to modify
+ QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), false);
+
+ // ..but SelectAll is awalys enabled
+ QCOMPARE(page->action(QWebPage::SelectAll)->isEnabled(), true);
+
+ // Verify hasSelection returns false since there is no selection yet...
+ QCOMPARE(page->hasSelection(), false);
+
+ // this will select the first paragraph
+ QString selectScript = "var range = document.createRange(); " \
+ "var node = document.getElementById(\"one\"); " \
+ "range.selectNode(node); " \
+ "getSelection().addRange(range);";
+ page->mainFrame()->evaluateJavaScript(selectScript);
+ QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox"));
+ QRegExp regExp(" style=\".*\"");
+ regExp.setMinimal(true);
+ QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("<span class=\"Apple-style-span\"><p id=\"one\">The quick brown fox</p></span>"));
+
+ // Make sure hasSelection returns true, since there is selected text now...
+ QCOMPARE(page->hasSelection(), true);
+
+ // here the actions are enabled after a selection has been created
+ QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true);
+
+ // make it editable before navigating the cursor
+ page->setContentEditable(true);
+
+ // cursor will be before the word "The", this makes sure there is a charet
+ page->triggerAction(QWebPage::MoveToStartOfDocument);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // here the actions are enabled after contentEditable is true
+ QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true);
+
+ delete page;
+}
+
+void tst_QWebPage::textEditing()
+{
+ CursorTrackedPage* page = new CursorTrackedPage;
+ QString content("<html><body><p id=one>The quick brown fox</p>" \
+ "<p id=two>jumps over the lazy dog</p>" \
+ "<p>May the source<br/>be with you!</p></body></html>");
+ page->mainFrame()->setHtml(content);
+
+ // these actions must exist
+ QVERIFY(page->action(QWebPage::Cut) != 0);
+ QVERIFY(page->action(QWebPage::Copy) != 0);
+ QVERIFY(page->action(QWebPage::Paste) != 0);
+ QVERIFY(page->action(QWebPage::DeleteStartOfWord) != 0);
+ QVERIFY(page->action(QWebPage::DeleteEndOfWord) != 0);
+ QVERIFY(page->action(QWebPage::SetTextDirectionDefault) != 0);
+ QVERIFY(page->action(QWebPage::SetTextDirectionLeftToRight) != 0);
+ QVERIFY(page->action(QWebPage::SetTextDirectionRightToLeft) != 0);
+ QVERIFY(page->action(QWebPage::ToggleBold) != 0);
+ QVERIFY(page->action(QWebPage::ToggleItalic) != 0);
+ QVERIFY(page->action(QWebPage::ToggleUnderline) != 0);
+ QVERIFY(page->action(QWebPage::InsertParagraphSeparator) != 0);
+ QVERIFY(page->action(QWebPage::InsertLineSeparator) != 0);
+ QVERIFY(page->action(QWebPage::PasteAndMatchStyle) != 0);
+ QVERIFY(page->action(QWebPage::RemoveFormat) != 0);
+ QVERIFY(page->action(QWebPage::ToggleStrikethrough) != 0);
+ QVERIFY(page->action(QWebPage::ToggleSubscript) != 0);
+ QVERIFY(page->action(QWebPage::ToggleSuperscript) != 0);
+ QVERIFY(page->action(QWebPage::InsertUnorderedList) != 0);
+ QVERIFY(page->action(QWebPage::InsertOrderedList) != 0);
+ QVERIFY(page->action(QWebPage::Indent) != 0);
+ QVERIFY(page->action(QWebPage::Outdent) != 0);
+ QVERIFY(page->action(QWebPage::AlignCenter) != 0);
+ QVERIFY(page->action(QWebPage::AlignJustified) != 0);
+ QVERIFY(page->action(QWebPage::AlignLeft) != 0);
+ QVERIFY(page->action(QWebPage::AlignRight) != 0);
+
+ // right now they are disabled because contentEditable is false
+ QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), false);
+
+ // Select everything
+ page->triggerAction(QWebPage::SelectAll);
+
+ // make sure it is enabled since there is a selection
+ QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), true);
+
+ // make it editable before navigating the cursor
+ page->setContentEditable(true);
+
+ // clear the selection
+ page->triggerAction(QWebPage::MoveToStartOfDocument);
+ QVERIFY(page->isSelectionCollapsed());
+ QCOMPARE(page->selectionStartOffset(), 0);
+
+ // make sure it is disabled since there isn't a selection
+ QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), false);
+
+ // here the actions are enabled after contentEditable is true
+ QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), true);
+
+ // make sure these are disabled since there isn't a selection
+ QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false);
+ QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false);
+
+ // make sure everything is selected
+ page->triggerAction(QWebPage::SelectAll);
+
+ // this is only true if there is an editable selection
+ QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), true);
+ QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), true);
+
+ delete page;
+}
+
+void tst_QWebPage::requestCache()
+{
+ TestPage page;
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+
+ page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(page.navigations.count(), 1);
+
+ page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>"));
+ QTRY_COMPARE(loadSpy.count(), 2);
+ QTRY_COMPARE(page.navigations.count(), 2);
+
+ page.triggerAction(QWebPage::Stop);
+ QVERIFY(page.history()->canGoBack());
+ page.triggerAction(QWebPage::Back);
+
+ QTRY_COMPARE(loadSpy.count(), 3);
+ QTRY_COMPARE(page.navigations.count(), 3);
+ QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
+ (int)QNetworkRequest::PreferNetwork);
+ QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
+ (int)QNetworkRequest::PreferNetwork);
+ QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
+ (int)QNetworkRequest::PreferCache);
+}
+
+void tst_QWebPage::loadCachedPage()
+{
+ TestPage page;
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+ page.settings()->setMaximumPagesInCache(3);
+
+ page.mainFrame()->load(QUrl("data:text/html,This is first page"));
+
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QTRY_COMPARE(page.navigations.count(), 1);
+
+ QUrl firstPageUrl = page.mainFrame()->url();
+ page.mainFrame()->load(QUrl("data:text/html,This is second page"));
+
+ QTRY_COMPARE(loadSpy.count(), 2);
+ QTRY_COMPARE(page.navigations.count(), 2);
+
+ page.triggerAction(QWebPage::Stop);
+ QVERIFY(page.history()->canGoBack());
+
+ QSignalSpy urlSpy(page.mainFrame(), SIGNAL(urlChanged(QUrl)));
+ QVERIFY(urlSpy.isValid());
+
+ page.triggerAction(QWebPage::Back);
+ ::waitForSignal(page.mainFrame(), SIGNAL(urlChanged(QUrl)));
+ QCOMPARE(urlSpy.size(), 1);
+
+ QList<QVariant> arguments1 = urlSpy.takeFirst();
+ QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl);
+
+}
+void tst_QWebPage::backActionUpdate()
+{
+ QWebView view;
+ QWebPage *page = view.page();
+ QAction *action = page->action(QWebPage::Back);
+ QVERIFY(!action->isEnabled());
+ QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool)));
+ QUrl url = QUrl("qrc:///resources/framedindex.html");
+ page->mainFrame()->load(url);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QVERIFY(!action->isEnabled());
+ QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10));
+ QTRY_COMPARE(loadSpy.count(), 2);
+
+ QVERIFY(action->isEnabled());
+}
+
+void frameAtHelper(QWebPage* webPage, QWebFrame* webFrame, QPoint framePosition)
+{
+ if (!webFrame)
+ return;
+
+ framePosition += QPoint(webFrame->pos());
+ QList<QWebFrame*> children = webFrame->childFrames();
+ for (int i = 0; i < children.size(); ++i) {
+ if (children.at(i)->childFrames().size() > 0)
+ frameAtHelper(webPage, children.at(i), framePosition);
+
+ QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size());
+ QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft()));
+ }
+}
+
+void tst_QWebPage::frameAt()
+{
+ QWebView webView;
+ QWebPage* webPage = webView.page();
+ QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool)));
+ QUrl url = QUrl("qrc:///resources/iframe.html");
+ webPage->mainFrame()->load(url);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos());
+}
+
+void tst_QWebPage::inputMethods_data()
+{
+ QTest::addColumn<QString>("viewType");
+ QTest::newRow("QWebView") << "QWebView";
+ QTest::newRow("QGraphicsWebView") << "QGraphicsWebView";
+}
+
+static Qt::InputMethodHints inputMethodHints(QObject* object)
+{
+ if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object))
+ return o->inputMethodHints();
+ if (QWidget* w = qobject_cast<QWidget*>(object))
+ return w->inputMethodHints();
+ return Qt::InputMethodHints();
+}
+
+static bool inputMethodEnabled(QObject* object)
+{
+ if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object))
+ return o->flags() & QGraphicsItem::ItemAcceptsInputMethod;
+ if (QWidget* w = qobject_cast<QWidget*>(object))
+ return w->testAttribute(Qt::WA_InputMethodEnabled);
+ return false;
+}
+
+static void clickOnPage(QWebPage* page, const QPoint& position)
+{
+ QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ page->event(&evpres);
+ QMouseEvent evrel(QEvent::MouseButtonRelease, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ page->event(&evrel);
+}
+
+void tst_QWebPage::inputMethods()
+{
+ QFETCH(QString, viewType);
+ QWebPage* page = new QWebPage;
+ QObject* view = 0;
+ QObject* container = 0;
+ if (viewType == "QWebView") {
+ QWebView* wv = new QWebView;
+ wv->setPage(page);
+ view = wv;
+ container = view;
+ } else if (viewType == "QGraphicsWebView") {
+ QGraphicsWebView* wv = new QGraphicsWebView;
+ wv->setPage(page);
+ view = wv;
+
+ QGraphicsView* gv = new QGraphicsView;
+ QGraphicsScene* scene = new QGraphicsScene(gv);
+ gv->setScene(scene);
+ scene->addItem(wv);
+ wv->setGeometry(QRect(0, 0, 500, 500));
+
+ container = gv;
+ } else
+ QVERIFY2(false, "Unknown view type");
+
+ page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont");
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/><br>" \
+ "<input type='password'/>" \
+ "</body></html>");
+ page->mainFrame()->setFocus();
+
+ EventSpy viewEventSpy(container);
+
+ QWebElementCollection inputs = page->mainFrame()->documentElement().findAll("input");
+ QPoint textInputCenter = inputs.at(0).geometry().center();
+
+ clickOnPage(page, textInputCenter);
+
+ // This part of the test checks if the SIP (Software Input Panel) is triggered,
+ // which normally happens on mobile platforms, when a user input form receives
+ // a mouse click.
+ int inputPanel = 0;
+ if (viewType == "QWebView") {
+ if (QWebView* wv = qobject_cast<QWebView*>(view))
+ inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel);
+ } else if (viewType == "QGraphicsWebView") {
+ if (QGraphicsWebView* wv = qobject_cast<QGraphicsWebView*>(view))
+ inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel);
+ }
+
+ // For non-mobile platforms RequestSoftwareInputPanel event is not called
+ // because there is no SIP (Software Input Panel) triggered. In the case of a
+ // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked
+ // and the RequestSoftwareInputPanel event is called. For these two situations
+ // this part of the test can verified as the checks below.
+ if (inputPanel)
+ QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
+ else
+ QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
+ viewEventSpy.clear();
+
+ clickOnPage(page, textInputCenter);
+ QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
+
+ //ImMicroFocus
+ QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus);
+ QRect focusRect = variant.toRect();
+ QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft()));
+
+ //ImFont
+ variant = page->inputMethodQuery(Qt::ImFont);
+ QFont font = variant.value<QFont>();
+ QCOMPARE(page->settings()->fontFamily(QWebSettings::SerifFont), font.family());
+
+ QList<QInputMethodEvent::Attribute> inputAttributes;
+
+ //Insert text.
+ {
+ QInputMethodEvent eventText("QtWebKit", inputAttributes);
+ QSignalSpy signalSpy(page, SIGNAL(microFocusChanged()));
+ page->event(&eventText);
+ QCOMPARE(signalSpy.count(), 0);
+ }
+
+ {
+ QInputMethodEvent eventText("", inputAttributes);
+ eventText.setCommitString(QString("QtWebKit"), 0, 0);
+ page->event(&eventText);
+ }
+
+ //ImMaximumTextLength
+ variant = page->inputMethodQuery(Qt::ImMaximumTextLength);
+ QCOMPARE(20, variant.toInt());
+
+ //Set selection
+ inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant());
+ QInputMethodEvent eventSelection("",inputAttributes);
+ page->event(&eventSelection);
+
+ //ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ int anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 3);
+
+ //ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ int cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 5);
+
+ //ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ QString selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString("eb"));
+
+ //Set selection with negative length
+ inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant());
+ QInputMethodEvent eventSelection3("",inputAttributes);
+ page->event(&eventSelection3);
+
+ //ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 1);
+
+ //ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 6);
+
+ //ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString("tWebK"));
+
+ //ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ QString value = variant.value<QString>();
+ QCOMPARE(value, QString("QtWebKit"));
+
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ // Clear the selection, so the next test does not clear any contents.
+ QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant());
+ attributes.append(newSelection);
+ QInputMethodEvent event("composition", attributes);
+ page->event(&event);
+ }
+
+ // A ongoing composition should not change the surrounding text before it is committed.
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ value = variant.value<QString>();
+ QCOMPARE(value, QString("QtWebKit"));
+
+ // Cancel current composition first
+ inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant());
+ QInputMethodEvent eventSelection4("", inputAttributes);
+ page->event(&eventSelection4);
+
+ // START - Tests for Selection when the Editor is NOT in Composition mode
+
+ // LEFT to RIGHT selection
+ // Deselect the selection by sending MouseButtonPress events
+ // This moves the current cursor to the end of the text
+ clickOnPage(page, textInputCenter);
+
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QString(), attributes);
+ event.setCommitString("XXX", 0, 0);
+ page->event(&event);
+ event.setCommitString(QString(), -2, 2); // Erase two characters.
+ page->event(&event);
+ event.setCommitString(QString(), -1, 1); // Erase one character.
+ page->event(&event);
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ value = variant.value<QString>();
+ QCOMPARE(value, QString("QtWebKit"));
+ }
+
+ //Move to the start of the line
+ page->triggerAction(QWebPage::MoveToStartOfLine);
+
+ QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
+ QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier);
+
+ //Move 2 characters RIGHT
+ for (int j = 0; j < 2; ++j) {
+ page->event(&keyRightEventPress);
+ page->event(&keyRightEventRelease);
+ }
+
+ //Select to the end of the line
+ page->triggerAction(QWebPage::SelectEndOfLine);
+
+ //ImAnchorPosition QtWebKit
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 2);
+
+ //ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 8);
+
+ //ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString("WebKit"));
+
+ //RIGHT to LEFT selection
+ //Deselect the selection (this moves the current cursor to the end of the text)
+ clickOnPage(page, textInputCenter);
+
+ //ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 8);
+
+ //ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 8);
+
+ //ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
+ QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier);
+
+ //Move 2 characters LEFT
+ for (int i = 0; i < 2; ++i) {
+ page->event(&keyLeftEventPress);
+ page->event(&keyLeftEventRelease);
+ }
+
+ //Select to the start of the line
+ page->triggerAction(QWebPage::SelectStartOfLine);
+
+ //ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 6);
+
+ //ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 0);
+
+ //ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString("QtWebK"));
+
+ //END - Tests for Selection when the Editor is not in Composition mode
+
+ //ImhHiddenText
+ QPoint passwordInputCenter = inputs.at(1).geometry().center();
+ clickOnPage(page, passwordInputCenter);
+
+ QVERIFY(inputMethodEnabled(view));
+ QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText);
+
+ clickOnPage(page, textInputCenter);
+ QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText));
+
+ page->mainFrame()->setHtml("<html><body><p>nothing to input here");
+ viewEventSpy.clear();
+
+ QWebElement para = page->mainFrame()->findFirstElement("p");
+ clickOnPage(page, para.geometry().center());
+
+ QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
+
+ //START - Test for sending empty QInputMethodEvent
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input3' value='QtWebKit2'/>" \
+ "</body></html>");
+ page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input3'); inputEle.focus(); inputEle.select();");
+
+ //Send empty QInputMethodEvent
+ QInputMethodEvent emptyEvent;
+ page->event(&emptyEvent);
+
+ QString inputValue = page->mainFrame()->evaluateJavaScript("document.getElementById('input3').value").toString();
+ QCOMPARE(inputValue, QString("QtWebKit2"));
+ //END - Test for sending empty QInputMethodEvent
+
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input4' value='QtWebKit inputMethod'/>" \
+ "</body></html>");
+ page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input4'); inputEle.focus(); inputEle.select();");
+
+ // Clear the selection, also cancel the ongoing composition if there is one.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant());
+ attributes.append(newSelection);
+ QInputMethodEvent event("", attributes);
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ QString surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("QtWebKit inputMethod"));
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 0);
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 0);
+
+ // 1. Insert a character to the begining of the line.
+ // Send temporary text, which makes the editor has composition 'm'.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("m", attributes);
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("QtWebKit inputMethod"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 0);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 0);
+
+ // Send temporary text, which makes the editor has composition 'n'.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("n", attributes);
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("QtWebKit inputMethod"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 0);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 0);
+
+ // Send commit text, which makes the editor conforms composition.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("o");
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oQtWebKit inputMethod"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 1);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 1);
+
+ // 2. insert a character to the middle of the line.
+ // Send temporary text, which makes the editor has composition 'd'.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("d", attributes);
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oQtWebKit inputMethod"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 1);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 1);
+
+ // Send commit text, which makes the editor conforms composition.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("e");
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethod"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 2);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 2);
+
+ // 3. Insert a character to the end of the line.
+ page->triggerAction(QWebPage::MoveToEndOfLine);
+
+ // Send temporary text, which makes the editor has composition 't'.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("t", attributes);
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethod"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 22);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 22);
+
+ // Send commit text, which makes the editor conforms composition.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("t");
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethodt"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 23);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 23);
+
+ // 4. Replace the selection.
+ page->triggerAction(QWebPage::SelectPreviousWord);
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString("inputMethodt"));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethodt"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 11);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 23);
+
+ // Send temporary text, which makes the editor has composition 'w'.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("w", attributes);
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oeQtWebKit "));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 11);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 11);
+
+ // Send commit text, which makes the editor conforms composition.
+ {
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event("", attributes);
+ event.setCommitString("2");
+ page->event(&event);
+ }
+
+ // ImCurrentSelection
+ variant = page->inputMethodQuery(Qt::ImCurrentSelection);
+ selectionValue = variant.value<QString>();
+ QCOMPARE(selectionValue, QString(""));
+
+ // ImSurroundingText
+ variant = page->inputMethodQuery(Qt::ImSurroundingText);
+ surroundingValue = variant.value<QString>();
+ QCOMPARE(surroundingValue, QString("oeQtWebKit 2"));
+
+ // ImCursorPosition
+ variant = page->inputMethodQuery(Qt::ImCursorPosition);
+ cursorPosition = variant.toInt();
+ QCOMPARE(cursorPosition, 12);
+
+ // ImAnchorPosition
+ variant = page->inputMethodQuery(Qt::ImAnchorPosition);
+ anchorPosition = variant.toInt();
+ QCOMPARE(anchorPosition, 12);
+
+ // Check sending RequestSoftwareInputPanel event
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input5' value='QtWebKit inputMethod'/>" \
+ "<div id='btnDiv' onclick='i=document.getElementById(&quot;input5&quot;); i.focus();'>abc</div>"\
+ "</body></html>");
+ QWebElement inputElement = page->mainFrame()->findFirstElement("div");
+ clickOnPage(page, inputElement.geometry().center());
+
+ QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
+
+ // START - Newline test for textarea
+ qApp->processEvents();
+ page->mainFrame()->setHtml("<html><body>" \
+ "<textarea rows='5' cols='1' id='input5' value=''/>" \
+ "</body></html>");
+ page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input5'); inputEle.focus(); inputEle.select();");
+ QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
+ page->event(&keyEnter);
+ QList<QInputMethodEvent::Attribute> attribs;
+
+ QInputMethodEvent eventText("\n", attribs);
+ page->event(&eventText);
+
+ QInputMethodEvent eventText2("third line", attribs);
+ page->event(&eventText2);
+ qApp->processEvents();
+
+ QString inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
+ QCOMPARE(inputValue2, QString("\n\nthird line"));
+ // END - Newline test for textarea
+
+ delete container;
+}
+
+void tst_QWebPage::inputMethodsTextFormat_data()
+{
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<int>("start");
+ QTest::addColumn<int>("length");
+
+ QTest::newRow("") << QString("") << 0 << 0;
+ QTest::newRow("Q") << QString("Q") << 0 << 1;
+ QTest::newRow("Qt") << QString("Qt") << 0 << 1;
+ QTest::newRow("Qt") << QString("Qt") << 0 << 2;
+ QTest::newRow("Qt") << QString("Qt") << 1 << 1;
+ QTest::newRow("Qt ") << QString("Qt ") << 0 << 1;
+ QTest::newRow("Qt ") << QString("Qt ") << 1 << 1;
+ QTest::newRow("Qt ") << QString("Qt ") << 2 << 1;
+ QTest::newRow("Qt ") << QString("Qt ") << 2 << -1;
+ QTest::newRow("Qt ") << QString("Qt ") << -2 << 3;
+ QTest::newRow("Qt ") << QString("Qt ") << 0 << 3;
+ QTest::newRow("Qt by") << QString("Qt by") << 0 << 1;
+ QTest::newRow("Qt by Nokia") << QString("Qt by Nokia") << 0 << 1;
+}
+
+
+void tst_QWebPage::inputMethodsTextFormat()
+{
+ QWebPage* page = new QWebPage;
+ QWebView* view = new QWebView;
+ view->setPage(page);
+ page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont");
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/>");
+ page->mainFrame()->evaluateJavaScript("document.getElementById('input1').focus()");
+ page->mainFrame()->setFocus();
+ view->show();
+
+ QFETCH(QString, string);
+ QFETCH(int, start);
+ QFETCH(int, length);
+
+ QList<QInputMethodEvent::Attribute> attrs;
+ QTextCharFormat format;
+ format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+ format.setUnderlineColor(Qt::red);
+ attrs.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, format));
+ QInputMethodEvent im(string, attrs);
+ page->event(&im);
+
+ QTest::qWait(1000);
+
+ delete view;
+}
+
+void tst_QWebPage::protectBindingsRuntimeObjectsFromCollector()
+{
+ QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
+
+ PluginPage* newPage = new PluginPage(m_view);
+ m_view->setPage(newPage);
+
+ m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+
+ m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='lineedit' id='mylineedit'/></body></html>"));
+ QTRY_COMPARE(loadSpy.count(), 1);
+
+ newPage->mainFrame()->evaluateJavaScript("function testme(text) { var lineedit = document.getElementById('mylineedit'); lineedit.setText(text); lineedit.selectAll(); }");
+
+ newPage->mainFrame()->evaluateJavaScript("testme('foo')");
+
+ DumpRenderTreeSupportQt::garbageCollectorCollect();
+
+ // don't crash!
+ newPage->mainFrame()->evaluateJavaScript("testme('bar')");
+}
+
+void tst_QWebPage::localURLSchemes()
+{
+ int i = QWebSecurityOrigin::localSchemes().size();
+
+ QWebSecurityOrigin::removeLocalScheme("file");
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
+ QWebSecurityOrigin::addLocalScheme("file");
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
+
+ QWebSecurityOrigin::removeLocalScheme("qrc");
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i - 1);
+ QWebSecurityOrigin::addLocalScheme("qrc");
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
+
+ QString myscheme = "myscheme";
+ QWebSecurityOrigin::addLocalScheme(myscheme);
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i + 1);
+ QVERIFY(QWebSecurityOrigin::localSchemes().contains(myscheme));
+ QWebSecurityOrigin::removeLocalScheme(myscheme);
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
+ QWebSecurityOrigin::removeLocalScheme(myscheme);
+ QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
+}
+
+static inline bool testFlag(QWebPage& webPage, QWebSettings::WebAttribute settingAttribute, const QString& jsObjectName, bool settingValue)
+{
+ webPage.settings()->setAttribute(settingAttribute, settingValue);
+ return webPage.mainFrame()->evaluateJavaScript(QString("(window.%1 != undefined)").arg(jsObjectName)).toBool();
+}
+
+void tst_QWebPage::testOptionalJSObjects()
+{
+ // Once a feature is enabled and the JS object is accessed turning off the setting will not turn off
+ // the visibility of the JS object any more. For this reason this test uses two QWebPage instances.
+ // Part of the test is to make sure that the QWebPage instances do not interfere with each other so turning on
+ // a feature for one instance will not turn it on for another.
+
+ QWebPage webPage1;
+ QWebPage webPage2;
+
+ webPage1.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl());
+ webPage2.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl());
+
+ QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue);
+ QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false);
+ QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", true), true);
+ QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue);
+ QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false);
+ QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), true);
+
+ QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false);
+ QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", true), true);
+ QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false);
+ QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", false), true);
+}
+
+void tst_QWebPage::testEnablePersistentStorage()
+{
+ QWebPage webPage;
+
+ // By default all persistent options should be disabled
+ QCOMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), false);
+ QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), false);
+ QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), false);
+ QVERIFY(webPage.settings()->iconDatabasePath().isEmpty());
+
+ QWebSettings::enablePersistentStorage();
+
+
+ QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), true);
+ QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), true);
+ QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), true);
+
+ QTRY_VERIFY(!webPage.settings()->offlineStoragePath().isEmpty());
+ QTRY_VERIFY(!webPage.settings()->offlineWebApplicationCachePath().isEmpty());
+ QTRY_VERIFY(!webPage.settings()->iconDatabasePath().isEmpty());
+}
+
+void tst_QWebPage::defaultTextEncoding()
+{
+ QWebFrame* mainFrame = m_page->mainFrame();
+
+ QString defaultCharset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
+ QVERIFY(!defaultCharset.isEmpty());
+ QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), defaultCharset);
+
+ m_page->settings()->setDefaultTextEncoding(QString("utf-8"));
+ QString charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
+ QCOMPARE(charset, QString("utf-8"));
+ QCOMPARE(m_page->settings()->defaultTextEncoding(), charset);
+
+ m_page->settings()->setDefaultTextEncoding(QString());
+ charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
+ QVERIFY(!charset.isEmpty());
+ QCOMPARE(charset, defaultCharset);
+
+ QWebSettings::globalSettings()->setDefaultTextEncoding(QString("utf-8"));
+ charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
+ QCOMPARE(charset, QString("utf-8"));
+ QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), charset);
+}
+
+class ErrorPage : public QWebPage
+{
+public:
+
+ ErrorPage(QWidget* parent = 0): QWebPage(parent)
+ {
+ }
+
+ virtual bool supportsExtension(Extension extension) const
+ {
+ return extension == ErrorPageExtension;
+ }
+
+ virtual bool extension(Extension, const ExtensionOption* option, ExtensionReturn* output)
+ {
+ ErrorPageExtensionReturn* errorPage = static_cast<ErrorPageExtensionReturn*>(output);
+
+ errorPage->contentType = "text/html";
+ errorPage->content = "error";
+ return true;
+ }
+};
+
+void tst_QWebPage::errorPageExtension()
+{
+ ErrorPage* page = new ErrorPage;
+ m_view->setPage(page);
+
+ QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
+
+ m_view->setUrl(QUrl("data:text/html,foo"));
+ QTRY_COMPARE(spyLoadFinished.count(), 1);
+
+ page->mainFrame()->setUrl(QUrl("http://non.existent/url"));
+ QTRY_COMPARE(spyLoadFinished.count(), 2);
+ QCOMPARE(page->mainFrame()->toPlainText(), QString("error"));
+ QCOMPARE(page->history()->count(), 2);
+ QCOMPARE(page->history()->currentItem().url(), QUrl("http://non.existent/url"));
+ QCOMPARE(page->history()->canGoBack(), true);
+ QCOMPARE(page->history()->canGoForward(), false);
+
+ page->triggerAction(QWebPage::Back);
+ QTRY_COMPARE(page->history()->canGoBack(), false);
+ QTRY_COMPARE(page->history()->canGoForward(), true);
+
+ page->triggerAction(QWebPage::Forward);
+ QTRY_COMPARE(page->history()->canGoBack(), true);
+ QTRY_COMPARE(page->history()->canGoForward(), false);
+
+ page->triggerAction(QWebPage::Back);
+ QTRY_COMPARE(page->history()->canGoBack(), false);
+ QTRY_COMPARE(page->history()->canGoForward(), true);
+ QTRY_COMPARE(page->history()->currentItem().url(), QUrl("data:text/html,foo"));
+
+ m_view->setPage(0);
+}
+
+void tst_QWebPage::errorPageExtensionInIFrames()
+{
+ ErrorPage* page = new ErrorPage;
+ m_view->setPage(page);
+
+ m_view->page()->mainFrame()->load(QUrl(
+ "data:text/html,"
+ "<h1>h1</h1>"
+ "<iframe src='data:text/html,<p/>p'></iframe>"
+ "<iframe src='http://non.existent/url'></iframe>"));
+ QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
+ QTRY_COMPARE(spyLoadFinished.count(), 1);
+
+ QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("error"));
+
+ m_view->setPage(0);
+}
+
+void tst_QWebPage::errorPageExtensionInFrameset()
+{
+ ErrorPage* page = new ErrorPage;
+ m_view->setPage(page);
+
+ m_view->load(QUrl("qrc:///resources/index.html"));
+
+ QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
+ QTRY_COMPARE(spyLoadFinished.count(), 1);
+ QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("error"));
+
+ m_view->setPage(0);
+}
+
+class FriendlyWebPage : public QWebPage
+{
+public:
+ friend class tst_QWebPage;
+};
+
+void tst_QWebPage::userAgentApplicationName()
+{
+ const QString oldApplicationName = QCoreApplication::applicationName();
+ FriendlyWebPage page;
+
+ const QString applicationNameMarker = QString::fromUtf8("StrangeName\342\210\236");
+ QCoreApplication::setApplicationName(applicationNameMarker);
+ QVERIFY(page.userAgentForUrl(QUrl()).contains(applicationNameMarker));
+
+ QCoreApplication::setApplicationName(oldApplicationName);
+}
+
+void tst_QWebPage::crashTests_LazyInitializationOfMainFrame()
+{
+ {
+ QWebPage webPage;
+ }
+ {
+ QWebPage webPage;
+ webPage.selectedText();
+ }
+ {
+ QWebPage webPage;
+ webPage.selectedHtml();
+ }
+ {
+ QWebPage webPage;
+ webPage.triggerAction(QWebPage::Back, true);
+ }
+ {
+ QWebPage webPage;
+ QPoint pos(10,10);
+ webPage.updatePositionDependentActions(pos);
+ }
+}
+
+static void takeScreenshot(QWebPage* page)
+{
+ QWebFrame* mainFrame = page->mainFrame();
+ page->setViewportSize(mainFrame->contentsSize());
+ QImage image(page->viewportSize(), QImage::Format_ARGB32);
+ QPainter painter(&image);
+ mainFrame->render(&painter);
+ painter.end();
+}
+
+void tst_QWebPage::screenshot_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>";
+ QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>");
+ QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode='transparent'></embed></body></html>");
+}
+
+void tst_QWebPage::screenshot()
+{
+ if (!QDir(TESTS_SOURCE_DIR).exists())
+ QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
+
+ QDir::setCurrent(TESTS_SOURCE_DIR);
+
+ QFETCH(QString, html);
+ QWebPage* page = new QWebPage;
+ page->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ QWebFrame* mainFrame = page->mainFrame();
+ mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
+ ::waitForSignal(mainFrame, SIGNAL(loadFinished(bool)), 2000);
+
+ // take screenshot without a view
+ takeScreenshot(page);
+
+ QWebView* view = new QWebView;
+ view->setPage(page);
+
+ // take screenshot when attached to a view
+ takeScreenshot(page);
+
+ delete page;
+ delete view;
+
+ QDir::setCurrent(QApplication::applicationDirPath());
+}
+
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+// https://bugs.webkit.org/show_bug.cgi?id=54138
+static void webGLScreenshotWithoutView(bool accelerated)
+{
+ QWebPage page;
+ page.settings()->setAttribute(QWebSettings::WebGLEnabled, true);
+ page.settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, accelerated);
+ QWebFrame* mainFrame = page.mainFrame();
+ mainFrame->setHtml("<html><body>"
+ "<canvas id='webgl' width='300' height='300'></canvas>"
+ "<script>document.getElementById('webgl').getContext('experimental-webgl')</script>"
+ "</body></html>");
+
+ takeScreenshot(&page);
+}
+
+void tst_QWebPage::acceleratedWebGLScreenshotWithoutView()
+{
+ webGLScreenshotWithoutView(true);
+}
+
+void tst_QWebPage::unacceleratedWebGLScreenshotWithoutView()
+{
+ webGLScreenshotWithoutView(false);
+}
+#endif
+
+void tst_QWebPage::originatingObjectInNetworkRequests()
+{
+ TestNetworkManager* networkManager = new TestNetworkManager(m_page);
+ m_page->setNetworkAccessManager(networkManager);
+ networkManager->requests.clear();
+
+ m_view->setHtml(QString("<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
+ "<head><meta http-equiv='refresh' content='1'></head>foo \">"
+ "<frame src=\"data:text/html,bar\"></frameset>"), QUrl());
+ QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
+
+ QCOMPARE(networkManager->requests.count(), 2);
+
+ QList<QWebFrame*> childFrames = m_page->mainFrame()->childFrames();
+ QCOMPARE(childFrames.count(), 2);
+
+ for (int i = 0; i < 2; ++i)
+ QVERIFY(qobject_cast<QWebFrame*>(networkManager->requests.at(i).originatingObject()) == childFrames.at(i));
+}
+
+/**
+ * Test fixups for https://bugs.webkit.org/show_bug.cgi?id=30914
+ *
+ * From JS we test the following conditions.
+ *
+ * OK + QString() => SUCCESS, empty string (but not null)
+ * OK + "text" => SUCCESS, "text"
+ * CANCEL + QString() => CANCEL, null string
+ * CANCEL + "text" => CANCEL, null string
+ */
+class JSPromptPage : public QWebPage {
+ Q_OBJECT
+public:
+ JSPromptPage()
+ {}
+
+ bool javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result)
+ {
+ if (msg == QLatin1String("test1")) {
+ *result = QString();
+ return true;
+ } else if (msg == QLatin1String("test2")) {
+ *result = QLatin1String("text");
+ return true;
+ } else if (msg == QLatin1String("test3")) {
+ *result = QString();
+ return false;
+ } else if (msg == QLatin1String("test4")) {
+ *result = QLatin1String("text");
+ return false;
+ }
+
+ qFatal("Unknown msg.");
+ return QWebPage::javaScriptPrompt(frame, msg, defaultValue, result);
+ }
+};
+
+void tst_QWebPage::testJSPrompt()
+{
+ JSPromptPage page;
+ bool res;
+
+ // OK + QString()
+ res = page.mainFrame()->evaluateJavaScript(
+ "var retval = prompt('test1');"
+ "retval=='' && retval.length == 0;").toBool();
+ QVERIFY(res);
+
+ // OK + "text"
+ res = page.mainFrame()->evaluateJavaScript(
+ "var retval = prompt('test2');"
+ "retval=='text' && retval.length == 4;").toBool();
+ QVERIFY(res);
+
+ // Cancel + QString()
+ res = page.mainFrame()->evaluateJavaScript(
+ "var retval = prompt('test3');"
+ "retval===null;").toBool();
+ QVERIFY(res);
+
+ // Cancel + "text"
+ res = page.mainFrame()->evaluateJavaScript(
+ "var retval = prompt('test4');"
+ "retval===null;").toBool();
+ QVERIFY(res);
+}
+
+class TestModalPage : public QWebPage
+{
+ Q_OBJECT
+public:
+ TestModalPage(QObject* parent = 0) : QWebPage(parent) {
+ }
+ virtual QWebPage* createWindow(WebWindowType) {
+ QWebPage* page = new TestModalPage();
+ connect(page, SIGNAL(windowCloseRequested()), page, SLOT(deleteLater()));
+ return page;
+ }
+};
+
+void tst_QWebPage::showModalDialog()
+{
+ TestModalPage page;
+ page.mainFrame()->setHtml(QString("<html></html>"));
+ QString res = page.mainFrame()->evaluateJavaScript("window.showModalDialog('javascript:window.returnValue=dialogArguments; window.close();', 'This is a test');").toString();
+ QCOMPARE(res, QString("This is a test"));
+}
+
+void tst_QWebPage::testStopScheduledPageRefresh()
+{
+ // Without QWebPage::StopScheduledPageRefresh
+ QWebPage page1;
+ page1.setNetworkAccessManager(new TestNetworkManager(&page1));
+ page1.mainFrame()->setHtml("<html><head>"
+ "<meta http-equiv=\"refresh\"content=\"0;URL=qrc:///resources/index.html\">"
+ "</head><body><h1>Page redirects immediately...</h1>"
+ "</body></html>");
+ QVERIFY(::waitForSignal(&page1, SIGNAL(loadFinished(bool))));
+ QTest::qWait(500);
+ QCOMPARE(page1.mainFrame()->url(), QUrl(QLatin1String("qrc:///resources/index.html")));
+
+ // With QWebPage::StopScheduledPageRefresh
+ QWebPage page2;
+ page2.setNetworkAccessManager(new TestNetworkManager(&page2));
+ page2.mainFrame()->setHtml("<html><head>"
+ "<meta http-equiv=\"refresh\"content=\"1;URL=qrc:///resources/index.html\">"
+ "</head><body><h1>Page redirect test with 1 sec timeout...</h1>"
+ "</body></html>");
+ page2.triggerAction(QWebPage::StopScheduledPageRefresh);
+ QTest::qWait(1500);
+ QCOMPARE(page2.mainFrame()->url().toString(), QLatin1String("about:blank"));
+}
+
+void tst_QWebPage::findText()
+{
+ m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>"));
+ m_page->triggerAction(QWebPage::SelectAll);
+ QVERIFY(!m_page->selectedText().isEmpty());
+ QVERIFY(!m_page->selectedHtml().isEmpty());
+ m_page->findText("");
+ QVERIFY(m_page->selectedText().isEmpty());
+ QVERIFY(m_page->selectedHtml().isEmpty());
+ QStringList words = (QStringList() << "foo" << "bar");
+ QRegExp regExp(" style=\".*\"");
+ regExp.setMinimal(true);
+ foreach (QString subString, words) {
+ m_page->findText(subString, QWebPage::FindWrapsAroundDocument);
+ QCOMPARE(m_page->selectedText(), subString);
+ QCOMPARE(m_page->selectedHtml().trimmed().replace(regExp, ""), QString("<span class=\"Apple-style-span\">%1</span>").arg(subString));
+ m_page->findText("");
+ QVERIFY(m_page->selectedText().isEmpty());
+ QVERIFY(m_page->selectedHtml().isEmpty());
+ }
+}
+
+struct ImageExtensionMap {
+ const char* extension;
+ const char* mimeType;
+};
+
+static const ImageExtensionMap extensionMap[] = {
+ { "bmp", "image/bmp" },
+ { "css", "text/css" },
+ { "gif", "image/gif" },
+ { "html", "text/html" },
+ { "htm", "text/html" },
+ { "ico", "image/x-icon" },
+ { "jpeg", "image/jpeg" },
+ { "jpg", "image/jpeg" },
+ { "js", "application/x-javascript" },
+ { "mng", "video/x-mng" },
+ { "pbm", "image/x-portable-bitmap" },
+ { "pgm", "image/x-portable-graymap" },
+ { "pdf", "application/pdf" },
+ { "png", "image/png" },
+ { "ppm", "image/x-portable-pixmap" },
+ { "rss", "application/rss+xml" },
+ { "svg", "image/svg+xml" },
+ { "text", "text/plain" },
+ { "tif", "image/tiff" },
+ { "tiff", "image/tiff" },
+ { "txt", "text/plain" },
+ { "xbm", "image/x-xbitmap" },
+ { "xml", "text/xml" },
+ { "xpm", "image/x-xpm" },
+ { "xsl", "text/xsl" },
+ { "xhtml", "application/xhtml+xml" },
+ { "wml", "text/vnd.wap.wml" },
+ { "wmlc", "application/vnd.wap.wmlc" },
+ { 0, 0 }
+};
+
+static QString getMimeTypeForExtension(const QString &ext)
+{
+ const ImageExtensionMap *e = extensionMap;
+ while (e->extension) {
+ if (ext.compare(QLatin1String(e->extension), Qt::CaseInsensitive) == 0)
+ return QLatin1String(e->mimeType);
+ ++e;
+ }
+
+ return QString();
+}
+
+void tst_QWebPage::supportedContentType()
+{
+ QStringList contentTypes;
+
+ // Add supported non image types...
+ contentTypes << "text/html" << "text/xml" << "text/xsl" << "text/plain" << "text/"
+ << "application/xml" << "application/xhtml+xml" << "application/vnd.wap.xhtml+xml"
+ << "application/rss+xml" << "application/atom+xml" << "application/json";
+
+ // Add supported image types...
+ Q_FOREACH(const QByteArray& imageType, QImageWriter::supportedImageFormats()) {
+ const QString mimeType = getMimeTypeForExtension(imageType);
+ if (!mimeType.isEmpty())
+ contentTypes << mimeType;
+ }
+
+ // Get the mime types supported by webkit...
+ const QStringList supportedContentTypes = m_page->supportedContentTypes();
+
+ Q_FOREACH(const QString& mimeType, contentTypes)
+ QVERIFY2(supportedContentTypes.contains(mimeType), QString("'%1' is not a supported content type!").arg(mimeType).toLatin1());
+
+ Q_FOREACH(const QString& mimeType, contentTypes)
+ QVERIFY2(m_page->supportsContentType(mimeType), QString("Cannot handle content types '%1'!").arg(mimeType).toLatin1());
+}
+
+
+void tst_QWebPage::navigatorCookieEnabled()
+{
+ m_page->networkAccessManager()->setCookieJar(0);
+ QVERIFY(!m_page->networkAccessManager()->cookieJar());
+ QVERIFY(!m_page->mainFrame()->evaluateJavaScript("navigator.cookieEnabled").toBool());
+
+ m_page->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
+ QVERIFY(m_page->networkAccessManager()->cookieJar());
+ QVERIFY(m_page->mainFrame()->evaluateJavaScript("navigator.cookieEnabled").toBool());
+}
+
+#ifdef Q_OS_MAC
+void tst_QWebPage::macCopyUnicodeToClipboard()
+{
+ QString unicodeText = QString::fromUtf8("αβγδεζηθικλμπ");
+ m_page->mainFrame()->setHtml(QString("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>%1</body></html>").arg(unicodeText));
+ m_page->triggerAction(QWebPage::SelectAll);
+ m_page->triggerAction(QWebPage::Copy);
+
+ QString clipboardData = QString::fromUtf8(QApplication::clipboard()->mimeData()->data(QLatin1String("text/html")));
+
+ QVERIFY(clipboardData.contains(QLatin1String("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />")));
+ QVERIFY(clipboardData.contains(unicodeText));
+}
+#endif
+
+void tst_QWebPage::contextMenuCopy()
+{
+ QWebView view;
+
+ view.setHtml("<a href=\"http://www.google.com\">You cant miss this</a>");
+
+ view.page()->triggerAction(QWebPage::SelectAll);
+ QVERIFY(!view.page()->selectedText().isEmpty());
+
+ QWebElement link = view.page()->mainFrame()->findFirstElement("a");
+ QPoint pos(link.geometry().center());
+ QContextMenuEvent event(QContextMenuEvent::Mouse, pos);
+ view.page()->swallowContextMenuEvent(&event);
+ view.page()->updatePositionDependentActions(pos);
+
+ QList<QMenu*> contextMenus = view.findChildren<QMenu*>();
+ QVERIFY(!contextMenus.isEmpty());
+ QMenu* contextMenu = contextMenus.first();
+ QVERIFY(contextMenu);
+
+ QList<QAction *> list = contextMenu->actions();
+ int index = list.indexOf(view.page()->action(QWebPage::Copy));
+ QVERIFY(index != -1);
+}
+
+void tst_QWebPage::deleteQWebViewTwice()
+{
+ for (int i = 0; i < 2; ++i) {
+ QMainWindow mainWindow;
+ QWebView* webView = new QWebView(&mainWindow);
+ mainWindow.setCentralWidget(webView);
+ webView->load(QUrl("qrc:///resources/frame_a.html"));
+ mainWindow.show();
+ connect(webView, SIGNAL(loadFinished(bool)), &mainWindow, SLOT(close()));
+ QApplication::instance()->exec();
+ }
+}
+
+class RepaintRequestedRenderer : public QObject {
+ Q_OBJECT
+public:
+ RepaintRequestedRenderer(QWebPage* page, QPainter* painter)
+ : m_page(page)
+ , m_painter(painter)
+ , m_recursionCount(0)
+ {
+ connect(m_page, SIGNAL(repaintRequested(QRect)), this, SLOT(onRepaintRequested(QRect)));
+ }
+
+signals:
+ void finished();
+
+private slots:
+ void onRepaintRequested(const QRect& rect)
+ {
+ QCOMPARE(m_recursionCount, 0);
+
+ m_recursionCount++;
+ m_page->mainFrame()->render(m_painter, rect);
+ m_recursionCount--;
+
+ QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
+ }
+
+private:
+ QWebPage* m_page;
+ QPainter* m_painter;
+ int m_recursionCount;
+};
+
+void tst_QWebPage::renderOnRepaintRequestedShouldNotRecurse()
+{
+ QSize viewportSize(720, 576);
+ QWebPage page;
+
+ QImage image(viewportSize, QImage::Format_ARGB32);
+ QPainter painter(&image);
+
+ page.setPreferredContentsSize(viewportSize);
+ page.setViewportSize(viewportSize);
+ RepaintRequestedRenderer r(&page, &painter);
+
+ page.mainFrame()->setHtml("zalan loves trunk", QUrl());
+
+ QVERIFY(::waitForSignal(&r, SIGNAL(finished())));
+}
+
+QTEST_MAIN(tst_QWebPage)
+#include "tst_qwebpage.moc"
diff --git a/Source/WebKit/qt/tests/qwebpage/tst_qwebpage.qrc b/Source/WebKit/qt/tests/qwebpage/tst_qwebpage.qrc
new file mode 100644
index 0000000..a0efabe
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebpage/tst_qwebpage.qrc
@@ -0,0 +1,13 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/index.html</file>
+ <file>resources/frame_a.html</file>
+ <file>resources/frame_c.html</file>
+ <file>resources/iframe.html</file>
+ <file>resources/iframe2.html</file>
+ <file>resources/iframe3.html</file>
+ <file>resources/framedindex.html</file>
+ <file>resources/content.html</file>
+</qresource>
+</RCC>
+
diff --git a/Source/WebKit/qt/tests/qwebplugindatabase/qwebplugindatabase.pro b/Source/WebKit/qt/tests/qwebplugindatabase/qwebplugindatabase.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebplugindatabase/qwebplugindatabase.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebplugindatabase/tst_qwebplugindatabase.cpp b/Source/WebKit/qt/tests/qwebplugindatabase/tst_qwebplugindatabase.cpp
new file mode 100644
index 0000000..1ee6206
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebplugindatabase/tst_qwebplugindatabase.cpp
@@ -0,0 +1,437 @@
+/*
+ Copyright (C) 2009 Jakub Wieczorek <faw217@gmail.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <QtTest/QtTest>
+
+#include <qdir.h>
+#include <qwebframe.h>
+#include <qwebpage.h>
+#include <qwebplugindatabase.h>
+#include <qwebsettings.h>
+#include <qvariant.h>
+
+class tst_QWebPluginDatabase : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void installedPlugins();
+ void searchPaths();
+ void null_data();
+ void null();
+ void pluginForMimeType();
+ void enabled();
+ void operatorequal_data();
+ void operatorequal();
+ void preferredPlugin();
+ void operatorassign_data();
+ void operatorassign();
+};
+
+typedef QWebPluginInfo::MimeType MimeType;
+
+void tst_QWebPluginDatabase::installedPlugins()
+{
+ QWebPage page;
+ page.settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ QWebFrame* frame = page.mainFrame();
+
+ QVariantMap jsPluginsMap = frame->evaluateJavaScript("window.navigator.plugins").toMap();
+ QList<QWebPluginInfo> plugins = QWebSettings::pluginDatabase()->plugins();
+ QCOMPARE(plugins, QWebSettings::pluginDatabase()->plugins());
+
+ int length = jsPluginsMap["length"].toInt();
+ QCOMPARE(length, plugins.count());
+
+ for (int i = 0; i < length; ++i) {
+ QWebPluginInfo plugin = plugins.at(i);
+
+ QVariantMap jsPlugin = frame->evaluateJavaScript(QString("window.navigator.plugins[%1]").arg(i)).toMap();
+ QString name = jsPlugin["name"].toString();
+ QString description = jsPlugin["description"].toString();
+ QString fileName = jsPlugin["filename"].toString();
+
+ QCOMPARE(plugin.name(), name);
+ QCOMPARE(plugin.description(), description);
+ QCOMPARE(QFileInfo(plugin.path()).fileName(), fileName);
+
+ QList<MimeType> mimeTypes;
+ int mimeTypesCount = jsPlugin["length"].toInt();
+
+ for (int j = 0; j < mimeTypesCount; ++j) {
+ QVariantMap jsMimeType = frame->evaluateJavaScript(QString("window.navigator.plugins[%1][%2]").arg(i).arg(j)).toMap();
+
+ MimeType mimeType;
+ mimeType.name = jsMimeType["type"].toString();
+ mimeType.description = jsMimeType["description"].toString();
+ mimeType.fileExtensions = jsMimeType["suffixes"].toString().split(',', QString::SkipEmptyParts);
+
+ mimeTypes.append(mimeType);
+ QVERIFY(plugin.supportsMimeType(mimeType.name));
+ }
+
+ QCOMPARE(plugin.mimeTypes(), mimeTypes);
+
+ QVERIFY(!plugin.isNull());
+ QVERIFY(plugin.isEnabled());
+ }
+}
+
+void tst_QWebPluginDatabase::searchPaths()
+{
+ QWebPluginDatabase* database = QWebSettings::pluginDatabase();
+ QList<QWebPluginInfo> plugins = database->plugins();
+ QStringList directories = database->searchPaths();
+ QCOMPARE(QWebPluginDatabase::defaultSearchPaths(), directories);
+
+ database->setSearchPaths(directories);
+ QCOMPARE(QWebPluginDatabase::defaultSearchPaths(), directories);
+ QCOMPARE(database->searchPaths(), directories);
+ QCOMPARE(database->plugins(), plugins);
+ database->refresh();
+ QCOMPARE(database->plugins(), plugins);
+
+ database->setSearchPaths(QStringList());
+ QCOMPARE(QWebPluginDatabase::defaultSearchPaths(), directories);
+ QCOMPARE(database->searchPaths(), QStringList());
+ QCOMPARE(database->plugins().count(), 0);
+
+ database->setSearchPaths(directories);
+ QCOMPARE(database->searchPaths(), directories);
+ database->addSearchPath(QDir::tempPath());
+ QCOMPARE(database->searchPaths().count(), directories.count() + 1);
+ QVERIFY(database->searchPaths().contains(QDir::tempPath()));
+ directories.append(QDir::tempPath());
+ QCOMPARE(database->searchPaths(), directories);
+
+ // As an empty set of search paths has been set, the database has been rebuilt
+ // from scratch after bringing the old path set back.
+ // Because the QWebPlugins no longer point to the same PluginPackages,
+ // the list is also no longer equal to the older one, even though it contains
+ // the same information.
+ QCOMPARE(database->plugins().count(), plugins.count());
+ plugins = database->plugins();
+ QCOMPARE(database->plugins(), plugins);
+
+ for (int i = (directories.count() - 1); i >= 0; --i) {
+ QDir directory(directories.at(i));
+ if (!directory.exists() || !directory.count())
+ directories.removeAt(i);
+ }
+
+ database->setSearchPaths(directories);
+ QCOMPARE(database->plugins(), plugins);
+ database->refresh();
+ QCOMPARE(database->plugins(), plugins);
+
+ database->setSearchPaths(QWebPluginDatabase::defaultSearchPaths());
+ directories = QWebPluginDatabase::defaultSearchPaths();
+ QCOMPARE(QWebPluginDatabase::defaultSearchPaths(), directories);
+ QCOMPARE(database->searchPaths(), directories);
+ QCOMPARE(database->plugins(), plugins);
+}
+
+Q_DECLARE_METATYPE(QWebPluginInfo)
+void tst_QWebPluginDatabase::null_data()
+{
+ QTest::addColumn<QWebPluginInfo>("plugin");
+ QTest::addColumn<bool>("null");
+
+ QTest::newRow("null") << QWebPluginInfo() << true;
+ QTest::newRow("foo") << QWebSettings::pluginDatabase()->pluginForMimeType("foobarbaz") << true;
+
+ QList<QWebPluginInfo> plugins = QWebSettings::pluginDatabase()->plugins();
+ for (int i = 0; i < plugins.count(); ++i)
+ QTest::newRow(QString::number(i).toUtf8().constData()) << plugins.at(i) << false;
+}
+
+void tst_QWebPluginDatabase::null()
+{
+ QFETCH(QWebPluginInfo, plugin);
+ QFETCH(bool, null);
+
+ QCOMPARE(plugin.isNull(), null);
+}
+
+void tst_QWebPluginDatabase::pluginForMimeType()
+{
+ QMultiMap<QString, QWebPluginInfo> pluginsMap;
+ QWebPluginDatabase* database = QWebSettings::pluginDatabase();
+ QList<QWebPluginInfo> plugins = database->plugins();
+
+ for (int i = 0; i < plugins.count(); ++i) {
+ QWebPluginInfo plugin = plugins.at(i);
+
+ QList<MimeType> mimeTypes = plugin.mimeTypes();
+ for (int j = 0; j < mimeTypes.count(); ++j) {
+ QString mimeType = mimeTypes.at(j).name;
+ pluginsMap.insert(mimeType, plugin);
+ QVERIFY(plugin.supportsMimeType(mimeType));
+ }
+ }
+
+ for (int i = 0; i < plugins.count(); ++i) {
+ QWebPluginInfo plugin = plugins.at(i);
+
+ QList<MimeType> mimeTypes = plugin.mimeTypes();
+ for (int j = 0; j < mimeTypes.count(); ++j) {
+ QString mimeType = mimeTypes.at(j).name;
+
+ QVERIFY(pluginsMap.count(mimeType) > 0);
+ if (pluginsMap.count(mimeType) > 1)
+ continue;
+
+ QWebPluginInfo pluginForMimeType = database->pluginForMimeType(mimeType);
+ QCOMPARE(pluginForMimeType, plugin);
+ database->setSearchPaths(database->searchPaths());
+ QCOMPARE(pluginForMimeType, plugin);
+ QCOMPARE(pluginForMimeType, database->pluginForMimeType(mimeType.toUpper()));
+ QCOMPARE(pluginForMimeType, database->pluginForMimeType(mimeType.toLower()));
+ QVERIFY(plugin.supportsMimeType(mimeType));
+ QVERIFY(!pluginForMimeType.isNull());
+ QVERIFY(!plugin.isNull());
+ }
+ }
+}
+
+void tst_QWebPluginDatabase::enabled()
+{
+ QMultiMap<QString, QWebPluginInfo> pluginsMap;
+ QWebPluginDatabase* database = QWebSettings::pluginDatabase();
+ QList<QWebPluginInfo> plugins = database->plugins();
+
+ for (int i = 0; i < plugins.count(); ++i) {
+ QWebPluginInfo plugin = plugins.at(i);
+
+ QList<MimeType> mimeTypes = plugin.mimeTypes();
+ for (int j = 0; j < mimeTypes.count(); ++j) {
+ QString mimeType = mimeTypes.at(j).name;
+ pluginsMap.insert(mimeType, plugin);
+ QVERIFY(plugin.supportsMimeType(mimeType));
+ }
+ }
+
+ QMultiMap<QString, QWebPluginInfo>::iterator it = pluginsMap.begin();
+ while (it != pluginsMap.end()) {
+ QString mimeType = it.key();
+ QWebPluginInfo plugin = it.value();
+ QWebPluginInfo pluginForMimeType = database->pluginForMimeType(mimeType);
+
+ QVERIFY(pluginsMap.count(mimeType) > 0);
+
+ if (pluginsMap.count(mimeType) == 1) {
+ QCOMPARE(plugin, pluginForMimeType);
+
+ QVERIFY(plugin.isEnabled());
+ QVERIFY(pluginForMimeType.isEnabled());
+ plugin.setEnabled(false);
+ QVERIFY(!plugin.isEnabled());
+ QVERIFY(!pluginForMimeType.isEnabled());
+ } else {
+ QVERIFY(plugin.isEnabled());
+ QVERIFY(pluginForMimeType.isEnabled());
+ plugin.setEnabled(false);
+ QVERIFY(!plugin.isEnabled());
+ }
+
+ QVERIFY(!plugin.isNull());
+ QVERIFY(!pluginForMimeType.isNull());
+
+ QWebPluginInfo pluginForMimeType2 = database->pluginForMimeType(mimeType);
+ if (pluginsMap.count(mimeType) == 1) {
+ QVERIFY(pluginForMimeType2 != plugin);
+ QVERIFY(pluginForMimeType2.isNull());
+ } else {
+ QVERIFY(pluginForMimeType2 != plugin);
+ QVERIFY(!pluginForMimeType2.isNull());
+ }
+
+ plugin.setEnabled(true);
+
+ ++it;
+ }
+}
+
+void tst_QWebPluginDatabase::operatorequal_data()
+{
+ QTest::addColumn<QWebPluginInfo>("first");
+ QTest::addColumn<QWebPluginInfo>("second");
+ QTest::addColumn<bool>("equal");
+
+ QWebPluginDatabase* database = QWebSettings::pluginDatabase();
+ QTest::newRow("null") << QWebPluginInfo() << QWebPluginInfo() << true;
+ QTest::newRow("application/x-shockwave-flash") << database->pluginForMimeType("application/x-shockwave-flash")
+ << database->pluginForMimeType("application/x-shockwave-flash") << true;
+ QTest::newRow("foo/bar-baz") << database->pluginForMimeType("foo/bar-baz")
+ << database->pluginForMimeType("foo/bar-baz") << true;
+
+ QList<QWebPluginInfo> plugins = database->plugins();
+ for (int i = 0; i < (plugins.count() - 1); ++i) {
+ QWebPluginInfo first = plugins.at(i);
+ QWebPluginInfo second = plugins.at(i + 1);
+
+ QTest::newRow(QString("%1==%2").arg(first.name(), second.name()).toUtf8().constData())
+ << first << second << false;
+ }
+}
+
+void tst_QWebPluginDatabase::operatorequal()
+{
+ QFETCH(QWebPluginInfo, first);
+ QFETCH(QWebPluginInfo, second);
+ QFETCH(bool, equal);
+
+ QCOMPARE(first == second, equal);
+}
+
+void tst_QWebPluginDatabase::preferredPlugin()
+{
+ QMultiMap<QString, QWebPluginInfo> pluginsMap;
+ QWebPluginDatabase* database = QWebSettings::pluginDatabase();
+ QList<QWebPluginInfo> plugins = database->plugins();
+
+ for (int i = 0; i < plugins.count(); ++i) {
+ QWebPluginInfo plugin = plugins.at(i);
+
+ QList<MimeType> mimeTypes = plugin.mimeTypes();
+ for (int j = 0; j < mimeTypes.count(); ++j) {
+ QString mimeType = mimeTypes.at(j).name;
+ pluginsMap.insert(mimeType, plugin);
+ }
+ }
+
+ QMultiMap<QString, QWebPluginInfo>::iterator it = pluginsMap.begin();
+ while (it != pluginsMap.end()) {
+ QString mimeType = it.key();
+
+ if (pluginsMap.count(mimeType) > 1) {
+ QList<QWebPluginInfo> pluginsForMimeType = pluginsMap.values(mimeType);
+ QWebPluginInfo plugin = database->pluginForMimeType(mimeType);
+ QVERIFY(plugin.supportsMimeType(mimeType));
+
+ pluginsForMimeType.removeAll(plugin);
+ for (int i = 0; i < pluginsForMimeType.count(); ++i) {
+ QWebPluginInfo anotherPlugin = pluginsForMimeType.at(i);
+ QVERIFY(plugin.supportsMimeType(mimeType));
+ QVERIFY(plugin != anotherPlugin);
+
+ QCOMPARE(database->pluginForMimeType(mimeType), plugin);
+ database->setPreferredPluginForMimeType(mimeType, anotherPlugin);
+ QCOMPARE(database->pluginForMimeType(mimeType), anotherPlugin);
+
+ anotherPlugin.setEnabled(false);
+ QCOMPARE(database->pluginForMimeType(mimeType), plugin);
+
+ anotherPlugin.setEnabled(true);
+ QCOMPARE(database->pluginForMimeType(mimeType), anotherPlugin);
+ database->setSearchPaths(database->searchPaths());
+ QCOMPARE(database->pluginForMimeType(mimeType), anotherPlugin);
+
+ database->setPreferredPluginForMimeType(mimeType, QWebPluginInfo());
+ QCOMPARE(database->pluginForMimeType(mimeType), plugin);
+ }
+ } else {
+ QWebPluginInfo plugin = database->pluginForMimeType(mimeType);
+ QCOMPARE(pluginsMap.value(mimeType), plugin);
+
+ database->setPreferredPluginForMimeType(mimeType, plugin);
+ QCOMPARE(database->pluginForMimeType(mimeType), plugin);
+
+ plugin.setEnabled(false);
+ QCOMPARE(database->pluginForMimeType(mimeType), QWebPluginInfo());
+ plugin.setEnabled(true);
+
+ database->setPreferredPluginForMimeType(mimeType, QWebPluginInfo());
+ QCOMPARE(database->pluginForMimeType(mimeType), plugin);
+ }
+
+ ++it;
+ }
+
+ if (pluginsMap.keys().count() >= 2) {
+ QStringList mimeTypes = pluginsMap.uniqueKeys();
+
+ QString mimeType1 = mimeTypes.at(0);
+ QString mimeType2 = mimeTypes.at(1);
+ QWebPluginInfo plugin1 = database->pluginForMimeType(mimeType1);
+ QWebPluginInfo plugin2 = database->pluginForMimeType(mimeType2);
+
+ int i = 2;
+ while (plugin2.supportsMimeType(mimeType1)
+ && !mimeType2.isEmpty()
+ && i < mimeTypes.count()) {
+ mimeType2 = mimeTypes.at(i);
+ plugin2 = database->pluginForMimeType(mimeType2);
+ ++i;
+ }
+
+ plugin1 = database->pluginForMimeType(mimeType1);
+ QVERIFY(plugin1.supportsMimeType(mimeType1));
+ QVERIFY(!plugin1.isNull());
+ plugin2 = database->pluginForMimeType(mimeType2);
+ QVERIFY(plugin2.supportsMimeType(mimeType2));
+ QVERIFY(!plugin2.isNull());
+
+ database->setPreferredPluginForMimeType(mimeType2, plugin1);
+ QVERIFY(!plugin1.supportsMimeType(mimeType2));
+ QCOMPARE(database->pluginForMimeType(mimeType2), plugin2);
+
+ database->setPreferredPluginForMimeType(mimeType1, plugin1);
+ QVERIFY(!plugin2.supportsMimeType(mimeType1));
+ QCOMPARE(database->pluginForMimeType(mimeType2), plugin2);
+ }
+}
+
+void tst_QWebPluginDatabase::operatorassign_data()
+{
+ QTest::addColumn<QWebPluginInfo>("first");
+ QTest::addColumn<QWebPluginInfo>("second");
+
+ QWebPluginDatabase* database = QWebSettings::pluginDatabase();
+ QTest::newRow("null") << QWebPluginInfo() << QWebPluginInfo();
+
+ QList<QWebPluginInfo> plugins = database->plugins();
+ for (int i = 0; i < (plugins.count() - 1); ++i) {
+ QWebPluginInfo first = plugins.at(i);
+ QWebPluginInfo second = plugins.at(i + 1);
+
+ QTest::newRow(QString("%1=%2").arg(first.name(), second.name()).toUtf8().constData()) << first << second;
+ }
+}
+
+void tst_QWebPluginDatabase::operatorassign()
+{
+ QFETCH(QWebPluginInfo, first);
+ QFETCH(QWebPluginInfo, second);
+
+ QWebPluginInfo info;
+ QCOMPARE(info.mimeTypes(), QList<MimeType>());
+ QCOMPARE(info = first, first);
+ QCOMPARE(info, first);
+ QCOMPARE(info.mimeTypes(), first.mimeTypes());
+ QCOMPARE(info = second, second);
+ QCOMPARE(info, second);
+ QCOMPARE(info.mimeTypes(), second.mimeTypes());
+ QCOMPARE(info = QWebPluginInfo(), QWebPluginInfo());
+ QCOMPARE(info.mimeTypes(), QList<MimeType>());
+}
+
+QTEST_MAIN(tst_QWebPluginDatabase)
+
+#include "tst_qwebplugindatabase.moc"
diff --git a/Source/WebKit/qt/tests/qwebview/.gitignore b/Source/WebKit/qt/tests/qwebview/.gitignore
new file mode 100644
index 0000000..444afe6
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/.gitignore
@@ -0,0 +1 @@
+qwebview
diff --git a/Source/WebKit/qt/tests/qwebview/qwebview.pro b/Source/WebKit/qt/tests/qwebview/qwebview.pro
new file mode 100644
index 0000000..e915d60
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/qwebview.pro
@@ -0,0 +1,3 @@
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
diff --git a/Source/WebKit/qt/tests/qwebview/resources/frame_a.html b/Source/WebKit/qt/tests/qwebview/resources/frame_a.html
new file mode 100644
index 0000000..9ff68f1
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/resources/frame_a.html
@@ -0,0 +1,2 @@
+<a href="http://google.com" target="frame_b"><img src="" width=100 height=100 alt="Google"></a>
+<a href="http://yahoo.com" target="frame_b"><img src="" width=100 height=100 alt="Yahoo"></a>
diff --git a/Source/WebKit/qt/tests/qwebview/resources/index.html b/Source/WebKit/qt/tests/qwebview/resources/index.html
new file mode 100644
index 0000000..c53ad09
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/resources/index.html
@@ -0,0 +1,4 @@
+<frameset cols="25%,75%">
+ <frame src="frame_a.html" name="frame_a">
+ <frame src="frame_b.html" name="frame_b">
+</frameset>
diff --git a/Source/WebKit/qt/tests/qwebview/resources/input_types.html b/Source/WebKit/qt/tests/qwebview/resources/input_types.html
new file mode 100644
index 0000000..2e893af
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/resources/input_types.html
@@ -0,0 +1,9 @@
+<html><body>
+<input type='text' maxlength='20' style='position: absolute; left: 10px; top: 0px; height: 50px; width: 100px;'/><br>
+<input type='password' style='position: absolute; left: 10px; top: 50px; height: 50px; width: 100px;'/><br>
+<input type='tel' style='position: absolute; left: 10px; top: 100px; height: 50px; width: 100px;'/><br>
+<input type='number' style='position: absolute; left: 10px; top: 150px; height: 50px; width: 100px;'/><br>
+<input type='email' style='position: absolute; left: 10px; top: 200px; height: 50px; width: 100px;'/><br>
+<input type='url' style='position: absolute; left: 10px; top: 250px; height: 50px; width: 100px;'/><br>
+<textarea style='position: absolute; left: 10px; top: 310px; height: 50px; width: 100px;' rows="2" cols="20">blah blah blah blah</textarea><br>
+</body></html>
diff --git a/Source/WebKit/qt/tests/qwebview/tst_qwebview.cpp b/Source/WebKit/qt/tests/qwebview/tst_qwebview.cpp
new file mode 100644
index 0000000..f557dc1
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/tst_qwebview.cpp
@@ -0,0 +1,516 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Torch Mobile Inc.
+ Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qtest.h>
+#include "../util.h"
+
+#include <qpainter.h>
+#include <qwebview.h>
+#include <qwebpage.h>
+#include <qnetworkrequest.h>
+#include <qdiriterator.h>
+#include <qwebkitversion.h>
+#include <qwebelement.h>
+#include <qwebframe.h>
+
+#ifdef Q_OS_SYMBIAN
+#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \
+ QVERIFY(actual & Qt::ImhNoAutoUppercase); \
+ QVERIFY(actual & Qt::ImhNoPredictiveText); \
+ QVERIFY(actual & expect);
+#else
+#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \
+ QVERIFY(actual == expect);
+#endif
+
+class tst_QWebView : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void renderingAfterMaxAndBack();
+ void renderHints();
+ void getWebKitVersion();
+
+ void reusePage_data();
+ void reusePage();
+ void microFocusCoordinates();
+ void focusInputTypes();
+
+ void crashTests();
+
+ void setPalette_data();
+ void setPalette();
+};
+
+// This will be called before the first test function is executed.
+// It is only called once.
+void tst_QWebView::initTestCase()
+{
+}
+
+// This will be called after the last test function is executed.
+// It is only called once.
+void tst_QWebView::cleanupTestCase()
+{
+}
+
+// This will be called before each test function is executed.
+void tst_QWebView::init()
+{
+}
+
+// This will be called after every test function.
+void tst_QWebView::cleanup()
+{
+}
+
+void tst_QWebView::renderHints()
+{
+ QWebView webView;
+
+ // default is only text antialiasing + smooth pixmap transform
+ QVERIFY(!(webView.renderHints() & QPainter::Antialiasing));
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::Antialiasing, true);
+ QVERIFY(webView.renderHints() & QPainter::Antialiasing);
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::Antialiasing, false);
+ QVERIFY(!(webView.renderHints() & QPainter::Antialiasing));
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ QVERIFY(!(webView.renderHints() & QPainter::Antialiasing));
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform);
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+
+ webView.setRenderHint(QPainter::SmoothPixmapTransform, false);
+ QVERIFY(webView.renderHints() & QPainter::TextAntialiasing);
+ QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform));
+ QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
+}
+
+void tst_QWebView::getWebKitVersion()
+{
+ QVERIFY(qWebKitVersion().toDouble() > 0);
+}
+
+void tst_QWebView::reusePage_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>";
+ QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>");
+ QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode=\"transparent\"></embed></body></html>");
+}
+
+void tst_QWebView::reusePage()
+{
+ if (!QDir(TESTS_SOURCE_DIR).exists())
+ QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
+
+ QDir::setCurrent(TESTS_SOURCE_DIR);
+
+ QFETCH(QString, html);
+ QWebView* view1 = new QWebView;
+ QPointer<QWebPage> page = new QWebPage;
+ view1->setPage(page);
+ page->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ QWebFrame* mainFrame = page->mainFrame();
+ mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
+ if (html.contains("</embed>")) {
+ // some reasonable time for the PluginStream to feed test.swf to flash and start painting
+ waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000);
+ }
+
+ view1->show();
+ QTest::qWaitForWindowShown(view1);
+ delete view1;
+ QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view
+
+ QWebView *view2 = new QWebView;
+ view2->setPage(page);
+ view2->show(); // in Windowless mode, you should still be able to see the plugin here
+ QTest::qWaitForWindowShown(view2);
+ delete view2;
+
+ delete page; // must not crash
+
+ QDir::setCurrent(QApplication::applicationDirPath());
+}
+
+// Class used in crashTests
+class WebViewCrashTest : public QObject {
+ Q_OBJECT
+ QWebView* m_view;
+public:
+ bool m_executed;
+
+
+ WebViewCrashTest(QWebView* view)
+ : m_view(view)
+ , m_executed(false)
+ {
+ view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int)));
+ }
+
+private slots:
+ void loading(int progress)
+ {
+ if (progress >= 20 && progress < 90) {
+ QVERIFY(!m_executed);
+ m_view->stop();
+ m_executed = true;
+ }
+ }
+};
+
+
+// Should not crash.
+void tst_QWebView::crashTests()
+{
+ // Test if loading can be stopped in loadProgress handler without crash.
+ // Test page should have frames.
+ QWebView view;
+ WebViewCrashTest tester(&view);
+ QUrl url("qrc:///resources/index.html");
+ view.load(url);
+ QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed.
+}
+
+void tst_QWebView::microFocusCoordinates()
+{
+ QWebPage* page = new QWebPage;
+ QWebView* webView = new QWebView;
+ webView->setPage( page );
+
+ page->mainFrame()->setHtml("<html><body>" \
+ "<input type='text' id='input1' style='font--family: serif' value='' maxlength='20'/><br>" \
+ "<canvas id='canvas1' width='500' height='500'></canvas>" \
+ "<input type='password'/><br>" \
+ "<canvas id='canvas2' width='500' height='500'></canvas>" \
+ "</body></html>");
+
+ page->mainFrame()->setFocus();
+
+ QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus);
+ QVERIFY(initialMicroFocus.isValid());
+
+ page->mainFrame()->scroll(0,50);
+
+ QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus);
+ QVERIFY(currentMicroFocus.isValid());
+
+ QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect());
+}
+
+void tst_QWebView::focusInputTypes()
+{
+ QWebView webView;
+ webView.show();
+ QTest::qWaitForWindowShown(&webView);
+
+ QUrl url("qrc:///resources/input_types.html");
+ QWebFrame* const mainFrame = webView.page()->mainFrame();
+ mainFrame->load(url);
+ mainFrame->setFocus();
+
+ QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool))));
+
+ // 'text' type
+ QWebElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN)
+ QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase);
+ QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText);
+#else
+ QVERIFY(webView.inputMethodHints() == Qt::ImhNone);
+#endif
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'password' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'tel' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDialableCharactersOnly);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'number' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDigitsOnly);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'email' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhEmailCharactersOnly);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'url' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhUrlCharactersOnly);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'password' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'text' type
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN)
+ QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase);
+ QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText);
+#else
+ QVERIFY(webView.inputMethodHints() == Qt::ImhNone);
+#endif
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'password' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+ VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText);
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+
+ // 'text area' field
+ inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea"));
+ QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
+#if defined(Q_OS_SYMBIAN)
+ QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase);
+ QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText);
+#else
+ QVERIFY(webView.inputMethodHints() == Qt::ImhNone);
+#endif
+ QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
+}
+
+void tst_QWebView::setPalette_data()
+{
+ QTest::addColumn<bool>("active");
+ QTest::addColumn<bool>("background");
+ QTest::newRow("activeBG") << true << true;
+ QTest::newRow("activeFG") << true << false;
+ QTest::newRow("inactiveBG") << false << true;
+ QTest::newRow("inactiveFG") << false << false;
+}
+
+// Render a QWebView to a QImage twice, each time with a different palette set,
+// verify that images rendered are not the same, confirming WebCore usage of
+// custom palette on selections.
+void tst_QWebView::setPalette()
+{
+ QString html = "<html><head></head>"
+ "<body>"
+ "Some text here"
+ "</body>"
+ "</html>";
+
+ QFETCH(bool, active);
+ QFETCH(bool, background);
+
+ QWidget* activeView = 0;
+
+ // Use controlView to manage active/inactive state of test views by raising
+ // or lowering their position in the window stack.
+ QWebView controlView;
+ controlView.setHtml(html);
+
+ QWebView view1;
+
+ QPalette palette1;
+ QBrush brush1(Qt::red);
+ brush1.setStyle(Qt::SolidPattern);
+ if (active && background) {
+ // Rendered image must have red background on an active QWebView.
+ palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1);
+ } else if (active && !background) {
+ // Rendered image must have red foreground on an active QWebView.
+ palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1);
+ } else if (!active && background) {
+ // Rendered image must have red background on an inactive QWebView.
+ palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1);
+ } else if (!active && !background) {
+ // Rendered image must have red foreground on an inactive QWebView.
+ palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1);
+ }
+
+ view1.setPalette(palette1);
+ view1.setHtml(html);
+ view1.page()->setViewportSize(view1.page()->currentFrame()->contentsSize());
+ view1.show();
+
+ QTest::qWaitForWindowShown(&view1);
+
+ if (!active) {
+ controlView.show();
+ QTest::qWaitForWindowShown(&controlView);
+ activeView = &controlView;
+ controlView.activateWindow();
+ } else {
+ view1.activateWindow();
+ activeView = &view1;
+ }
+
+ QTRY_COMPARE(QApplication::activeWindow(), activeView);
+
+ view1.page()->triggerAction(QWebPage::SelectAll);
+
+ QImage img1(view1.page()->viewportSize(), QImage::Format_ARGB32);
+ QPainter painter1(&img1);
+ view1.page()->currentFrame()->render(&painter1);
+ painter1.end();
+ view1.close();
+ controlView.close();
+
+ QWebView view2;
+
+ QPalette palette2;
+ QBrush brush2(Qt::blue);
+ brush2.setStyle(Qt::SolidPattern);
+ if (active && background) {
+ // Rendered image must have blue background on an active QWebView.
+ palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2);
+ } else if (active && !background) {
+ // Rendered image must have blue foreground on an active QWebView.
+ palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2);
+ } else if (!active && background) {
+ // Rendered image must have blue background on an inactive QWebView.
+ palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2);
+ } else if (!active && !background) {
+ // Rendered image must have blue foreground on an inactive QWebView.
+ palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2);
+ }
+
+ view2.setPalette(palette2);
+ view2.setHtml(html);
+ view2.page()->setViewportSize(view2.page()->currentFrame()->contentsSize());
+ view2.show();
+
+ QTest::qWaitForWindowShown(&view2);
+
+ if (!active) {
+ controlView.show();
+ QTest::qWaitForWindowShown(&controlView);
+ activeView = &controlView;
+ controlView.activateWindow();
+ } else {
+ view2.activateWindow();
+ activeView = &view2;
+ }
+
+ QTRY_COMPARE(QApplication::activeWindow(), activeView);
+
+ view2.page()->triggerAction(QWebPage::SelectAll);
+
+ QImage img2(view2.page()->viewportSize(), QImage::Format_ARGB32);
+ QPainter painter2(&img2);
+ view2.page()->currentFrame()->render(&painter2);
+ painter2.end();
+
+ view2.close();
+ controlView.close();
+
+ QVERIFY(img1 != img2);
+}
+
+void tst_QWebView::renderingAfterMaxAndBack()
+{
+ QUrl url = QUrl("data:text/html,<html><head></head>"
+ "<body width=1024 height=768 bgcolor=red>"
+ "</body>"
+ "</html>");
+
+ QWebView view;
+ view.page()->mainFrame()->load(url);
+ QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool))));
+ view.show();
+
+ view.page()->settings()->setMaximumPagesInCache(3);
+
+ QTest::qWaitForWindowShown(&view);
+
+ QPixmap reference(view.page()->viewportSize());
+ reference.fill(Qt::red);
+
+ QPixmap image(view.page()->viewportSize());
+ QPainter painter(&image);
+ view.page()->currentFrame()->render(&painter);
+
+ QCOMPARE(image, reference);
+
+ QUrl url2 = QUrl("data:text/html,<html><head></head>"
+ "<body width=1024 height=768 bgcolor=blue>"
+ "</body>"
+ "</html>");
+ view.page()->mainFrame()->load(url2);
+
+ QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool))));
+
+ view.showMaximized();
+
+ QTest::qWaitForWindowShown(&view);
+
+ QPixmap reference2(view.page()->viewportSize());
+ reference2.fill(Qt::blue);
+
+ QPixmap image2(view.page()->viewportSize());
+ QPainter painter2(&image2);
+ view.page()->currentFrame()->render(&painter2);
+
+ QCOMPARE(image2, reference2);
+
+ view.back();
+
+ QPixmap reference3(view.page()->viewportSize());
+ reference3.fill(Qt::red);
+ QPixmap image3(view.page()->viewportSize());
+ QPainter painter3(&image3);
+ view.page()->currentFrame()->render(&painter3);
+
+ QCOMPARE(image3, reference3);
+}
+
+QTEST_MAIN(tst_QWebView)
+#include "tst_qwebview.moc"
+
diff --git a/Source/WebKit/qt/tests/qwebview/tst_qwebview.qrc b/Source/WebKit/qt/tests/qwebview/tst_qwebview.qrc
new file mode 100644
index 0000000..8710a9a
--- /dev/null
+++ b/Source/WebKit/qt/tests/qwebview/tst_qwebview.qrc
@@ -0,0 +1,8 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/index.html</file>
+ <file>resources/frame_a.html</file>
+ <file>resources/input_types.html</file>
+</qresource>
+</RCC>
+
diff --git a/Source/WebKit/qt/tests/resources/image2.png b/Source/WebKit/qt/tests/resources/image2.png
new file mode 100644
index 0000000..8d70364
--- /dev/null
+++ b/Source/WebKit/qt/tests/resources/image2.png
Binary files differ
diff --git a/Source/WebKit/qt/tests/resources/test.swf b/Source/WebKit/qt/tests/resources/test.swf
new file mode 100644
index 0000000..8952982
--- /dev/null
+++ b/Source/WebKit/qt/tests/resources/test.swf
Binary files differ
diff --git a/Source/WebKit/qt/tests/tests.pri b/Source/WebKit/qt/tests/tests.pri
new file mode 100644
index 0000000..3b0c358
--- /dev/null
+++ b/Source/WebKit/qt/tests/tests.pri
@@ -0,0 +1,36 @@
+TEMPLATE = app
+CONFIG -= app_bundle
+
+VPATH += $$_PRO_FILE_PWD_
+# Add the tst_ prefix, In QTDIR_build it's done by qttest_p4.prf
+CONFIG(QTDIR_build) { load(qttest_p4) }
+ELSE { TARGET = tst_$$TARGET }
+
+# Load mobilityconfig if Qt Mobility is available
+load(mobilityconfig, true)
+contains(MOBILITY_CONFIG, multimedia) {
+ # This define is used by tests depending on Qt Multimedia
+ DEFINES -= WTF_USE_QT_MULTIMEDIA=0
+ DEFINES += WTF_USE_QT_MULTIMEDIA=1
+}
+
+SOURCES += $${TARGET}.cpp
+INCLUDEPATH += \
+ $$PWD \
+ $$PWD/../Api
+
+include(../../../WebKit.pri)
+QT += testlib network
+contains(QT_CONFIG, declarative): QT += declarative
+
+QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+
+symbian {
+ TARGET.CAPABILITY = ReadUserData WriteUserData NetworkServices
+}
+
+# This define is used by some tests to look up resources in the source tree
+!symbian: DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\"
+
+DEFINES -= QT_ASCII_CAST_WARNINGS
+
diff --git a/Source/WebKit/qt/tests/tests.pro b/Source/WebKit/qt/tests/tests.pro
new file mode 100644
index 0000000..5fffd7b
--- /dev/null
+++ b/Source/WebKit/qt/tests/tests.pro
@@ -0,0 +1,8 @@
+
+TEMPLATE = subdirs
+SUBDIRS = qwebframe qwebpage qwebelement qgraphicswebview qwebhistoryinterface qwebview qwebhistory qwebinspector hybridPixmap MIMESniffing
+contains(QT_CONFIG, declarative): SUBDIRS += qdeclarativewebview
+SUBDIRS += benchmarks/painting benchmarks/loading
+contains(DEFINES, ENABLE_WEBGL=1) {
+ SUBDIRS += benchmarks/webgl
+}
diff --git a/Source/WebKit/qt/tests/util.h b/Source/WebKit/qt/tests/util.h
new file mode 100644
index 0000000..c61bc6b
--- /dev/null
+++ b/Source/WebKit/qt/tests/util.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+// Functions and macros that really need to be in QTestLib
+
+#include <QEventLoop>
+#include <QSignalSpy>
+#include <QTimer>
+
+#if !defined(TESTS_SOURCE_DIR)
+#define TESTS_SOURCE_DIR ""
+#endif
+
+/**
+ * Starts an event loop that runs until the given signal is received.
+ * Optionally the event loop
+ * can return earlier on a timeout.
+ *
+ * \return \p true if the requested signal was received
+ * \p false on timeout
+ */
+static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000)
+{
+ QEventLoop loop;
+ QObject::connect(obj, signal, &loop, SLOT(quit()));
+ QTimer timer;
+ QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
+ if (timeout > 0) {
+ QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+ timer.setSingleShot(true);
+ timer.start(timeout);
+ }
+ loop.exec();
+ return timeoutSpy.isEmpty();
+}
+
+// Will try to wait for the condition while allowing event processing
+#define QTRY_VERIFY(__expr) \
+ do { \
+ const int __step = 50; \
+ const int __timeout = 5000; \
+ if (!(__expr)) { \
+ QTest::qWait(0); \
+ } \
+ for (int __i = 0; __i < __timeout && !(__expr); __i+=__step) { \
+ QTest::qWait(__step); \
+ } \
+ QVERIFY(__expr); \
+ } while(0)
+
+// Will try to wait for the condition while allowing event processing
+#define QTRY_COMPARE(__expr, __expected) \
+ do { \
+ const int __step = 50; \
+ const int __timeout = 5000; \
+ if ((__expr) != (__expected)) { \
+ QTest::qWait(0); \
+ } \
+ for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
+ QTest::qWait(__step); \
+ } \
+ QCOMPARE(__expr, __expected); \
+ } while(0)