test");
view.page()->updatePositionDependentActions(QPoint(0, 0));
QMenu* contextMenu = 0;
foreach (QObject* child, view.children()) {
contextMenu = qobject_cast(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*");
QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)));
m_view->setHtml(QString(""), 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("text"), 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("text"), 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(""), 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 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());
QTest::qWait(1000);
}
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 calls;
protected:
virtual QObject *createPlugin(const QString &classid, const QUrl &url,
const QStringList ¶mNames,
const QStringList ¶mValues)
{
QObject *result = 0;
if (classid == "pushbutton")
result = new QPushButton();
else if (classid == "lineedit")
result = new QLineEdit();
if (result)
result->setObjectName(classid);
calls.append(CallInfo(classid, url, paramNames, paramValues, result));
return result;
}
};
void tst_QWebPage::createPlugin()
{
QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
PluginPage* newPage = new PluginPage(m_view);
m_view->setPage(newPage);
// plugins not enabled by default, so the plugin shouldn't be loaded
m_view->setHtml(QString(""));
QTRY_COMPARE(loadSpy.count(), 1);
QCOMPARE(newPage->calls.count(), 0);
m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
// type has to be application/x-qt-plugin
m_view->setHtml(QString(""));
QTRY_COMPARE(loadSpy.count(), 2);
QCOMPARE(newPage->calls.count(), 0);
m_view->setHtml(QString(""));
QTRY_COMPARE(loadSpy.count(), 3);
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}"));
m_view->setHtml(QString("
"
"
"
"
"
"
"), QUrl("http://foo.bar.baz"));
QTRY_COMPARE(loadSpy.count(), 4);
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"));
}
m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, false);
m_view->setHtml(QString(""));
QTRY_COMPARE(loadSpy.count(), 5);
QCOMPARE(newPage->calls.count(), 0);
}
// Standard base class for template PluginTracerPage. In tests it is used as interface.
class PluginCounterPage : public QWebPage {
public:
int m_count;
QPointer 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 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(m_widget.data())->setParent(static_cast(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(parent);
break;
case QGraphicsWidgetType:
result = new PluginTracerPage(parent);
break;
default: {/*Oops*/};
}
return result;
}
static void prepareTestData()
{
QTest::addColumn("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("");
m_view->setHtml(content);
QVERIFY(page->m_widget);
QCOMPARE(page->m_count, 1);
// navigate away, the plugin widget should be destructed
m_view->setHtml("Hi");
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("");
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;
}
// import private API
void QWEBKIT_EXPORT qt_webpage_setGroupName(QWebPage* page, const QString& groupName);
QString QWEBKIT_EXPORT qt_webpage_groupName(QWebPage* 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"));
qt_webpage_setGroupName(view1.page(), "group1");
view2.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path2"));
qt_webpage_setGroupName(view2.page(), "group2");
QCOMPARE(qt_webpage_groupName(view1.page()), QString("group1"));
QCOMPARE(qt_webpage_groupName(view2.page()), QString("group2"));
view1.setHtml(QString(" "), QUrl("http://www.myexample.com"));
view2.setHtml(QString(" "), QUrl("http://www.myexample.com"));
view1.page()->mainFrame()->evaluateJavaScript("localStorage.test='value1';");
view2.page()->mainFrame()->evaluateJavaScript("localStorage.test='value2';");
view1.setHtml(QString(" "), QUrl("http://www.myexample.com"));
view2.setHtml(QString(" "), 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("The quick brown fox
jumps over the lazy dog
May the source be with you!
");
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"));
// 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("The quick brown fox
" \
"
jumps over the lazy dog
" \
"
May the source be with you!
");
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);
// 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"));
// 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("The quick brown fox" \
"
jumps over the lazy dog
" \
"
May the source be with you!
");
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,Click me"));
QTRY_COMPARE(loadSpy.count(), 1);
QTRY_COMPARE(page.navigations.count(), 1);
page.mainFrame()->setUrl(QString("data:text/html,Click me2"));
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::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:///frametest/index.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 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:///frametest/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("viewType");
QTest::newRow("QWebView") << "QWebView";
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
QTest::newRow("QGraphicsWebView") << "QGraphicsWebView";
#endif
}
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
static Qt::InputMethodHints inputMethodHints(QObject* object)
{
if (QGraphicsObject* o = qobject_cast(object))
return o->inputMethodHints();
if (QWidget* w = qobject_cast(object))
return w->inputMethodHints();
return Qt::InputMethodHints();
}
#endif
static bool inputMethodEnabled(QObject* object)
{
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
if (QGraphicsObject* o = qobject_cast(object))
return o->flags() & QGraphicsItem::ItemAcceptsInputMethod;
#endif
if (QWidget* w = qobject_cast(object))
return w->testAttribute(Qt::WA_InputMethodEnabled);
return false;
}
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;
}
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
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;
}
#endif
else
QVERIFY2(false, "Unknown view type");
page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont");
page->mainFrame()->setHtml("" \
" " \
"" \
"");
page->mainFrame()->setFocus();
EventSpy viewEventSpy(container);
QWebElementCollection inputs = page->mainFrame()->documentElement().findAll("input");
QMouseEvent evpres(QEvent::MouseButtonPress, inputs.at(0).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
page->event(&evpres);
QMouseEvent evrel(QEvent::MouseButtonRelease, inputs.at(0).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
page->event(&evrel);
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
#endif
viewEventSpy.clear();
page->event(&evpres);
page->event(&evrel);
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
#endif
//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();
QCOMPARE(page->settings()->fontFamily(QWebSettings::SerifFont), font.family());
QList 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);
}
#if QT_VERSION >= 0x040600
//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();
QCOMPARE(selectionValue, QString("eb"));
//Set selection with negative length
inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant());
QInputMethodEvent eventSelection2("",inputAttributes);
page->event(&eventSelection2);
//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();
QCOMPARE(selectionValue, QString("tWebK"));
#endif
//ImSurroundingText
variant = page->inputMethodQuery(Qt::ImSurroundingText);
QString value = variant.value();
QCOMPARE(value, QString("QtWebKit"));
#if QT_VERSION >= 0x040600
{
QList 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();
QCOMPARE(value, QString("QtWebKit"));
#endif
//ImhHiddenText
QMouseEvent evpresPassword(QEvent::MouseButtonPress, inputs.at(1).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
page->event(&evpresPassword);
QMouseEvent evrelPassword(QEvent::MouseButtonRelease, inputs.at(1).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
page->event(&evrelPassword);
QVERIFY(inputMethodEnabled(view));
#if QT_VERSION >= 0x040600
QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText);
page->event(&evpres);
page->event(&evrel);
QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText));
#endif
page->mainFrame()->setHtml("
nothing to input here");
viewEventSpy.clear();
QWebElement para = page->mainFrame()->findFirstElement("p");
{
QMouseEvent evpres(QEvent::MouseButtonPress, para.geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
page->event(&evpres);
QMouseEvent evrel(QEvent::MouseButtonRelease, para.geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
page->event(&evrel);
}
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
#endif
delete container;
}
// import a little DRT helper function to trigger the garbage collector
void QWEBKIT_EXPORT qt_drt_garbageCollector_collect();
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("
"));
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')");
qt_drt_garbageCollector_collect();
// 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);
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("test"), QUrl());
webPage2.currentFrame()->setHtml(QString("test"), 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();
// Give it some time to initialize - icon database needs it
QTest::qWait(1000);
QCOMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), true);
QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), true);
QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), true);
QVERIFY(!webPage.settings()->offlineStoragePath().isEmpty());
QVERIFY(!webPage.settings()->offlineWebApplicationCachePath().isEmpty());
QVERIFY(!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)
{
const ErrorPageExtensionOption* info = static_cast(option);
ErrorPageExtensionReturn* errorPage = static_cast(output);
if (info->frame == mainFrame()) {
errorPage->content = "data:text/html,error";
return true;
}
return false;
}
};
void tst_QWebPage::errorPageExtension()
{
ErrorPage* page = new ErrorPage;
m_view->setPage(page);
QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
page->mainFrame()->load(QUrl("qrc:///frametest/index.html"));
QTRY_COMPARE(spyLoadFinished.count(), 1);
page->mainFrame()->setUrl(QUrl("http://non.existent/url"));
QTest::qWait(2000);
QTRY_COMPARE(spyLoadFinished.count(), 2);
QCOMPARE(page->mainFrame()->toPlainText(), QString("data:text/html,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);
QTest::qWait(2000);
QCOMPARE(page->history()->canGoBack(), false);
QCOMPARE(page->history()->canGoForward(), true);
page->triggerAction(QWebPage::Forward);
QTest::qWait(2000);
QCOMPARE(page->history()->canGoBack(), true);
QCOMPARE(page->history()->canGoForward(), false);
page->triggerAction(QWebPage::Back);
QTest::qWait(2000);
QCOMPARE(page->history()->canGoBack(), false);
QCOMPARE(page->history()->canGoForward(), true);
QCOMPARE(page->history()->currentItem().url(), QUrl("qrc:///frametest/index.html"));
m_view->setPage(0);
}
void tst_QWebPage::crashTests_LazyInitializationOfMainFrame()
{
{
QWebPage webPage;
}
{
QWebPage webPage;
webPage.selectedText();
}
{
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("html");
QTest::newRow("WithoutPlugin") << "text";
QTest::newRow("WindowedPlugin") << QString("text");
QTest::newRow("WindowlessPlugin") << QString("text");
}
void tst_QWebPage::screenshot()
{
QDir::setCurrent(SRCDIR);
QFETCH(QString, html);
QWebPage* page = new QWebPage;
page->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
QWebFrame* mainFrame = page->mainFrame();
mainFrame->setHtml(html, QUrl::fromLocalFile(QDir::currentPath()));
if (html.contains("")) {
// some reasonable time for the PluginStream to feed test.swf to flash and start painting
QTest::qWait(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());
}
void tst_QWebPage::originatingObjectInNetworkRequests()
{
TestNetworkManager* networkManager = new TestNetworkManager(m_page);
m_page->setNetworkAccessManager(networkManager);
networkManager->requests.clear();
m_view->setHtml(QString("data:text/html,"), QUrl());
QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
QCOMPARE(networkManager->requests.count(), 2);
QList childFrames = m_page->mainFrame()->childFrames();
QCOMPARE(childFrames.count(), 2);
#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
for (int i = 0; i < 2; ++i)
QVERIFY(qobject_cast(networkManager->requests.at(i).originatingObject()) == childFrames.at(i));
#endif
}
/**
* 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);
}
QTEST_MAIN(tst_QWebPage)
#include "tst_qwebpage.moc"