Falkon Develop
Cross-platform Qt-based web browser
webhittestresult.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2015-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "webhittestresult.h"
19#include "webpage.h"
20
21#include <QWebEngineContextMenuRequest>
22
23WebHitTestResult::WebHitTestResult(const WebPage *page, const QPoint &pos)
24 : m_isNull(true)
25 , m_isContentEditable(false)
26 , m_isContentSelected(false)
27 , m_mediaPaused(false)
28 , m_mediaMuted(false)
29 , m_pos(pos)
30{
31 QString source = QL1S("(function() {"
32 "var e = document.elementFromPoint(%1, %2);"
33 "if (!e)"
34 " return;"
35 "function isMediaElement(e) {"
36 " return e.tagName.toLowerCase() == 'audio' || e.tagName.toLowerCase() == 'video';"
37 "}"
38 "function isEditableElement(e) {"
39 " if (e.isContentEditable)"
40 " return true;"
41 " if (e.tagName.toLowerCase() == 'input' || e.tagName.toLowerCase() == 'textarea')"
42 " return e.getAttribute('readonly') != 'readonly';"
43 " return false;"
44 "}"
45 "function isSelected(e) {"
46 " var selection = window.getSelection();"
47 " if (selection.type != 'Range')"
48 " return false;"
49 " return window.getSelection().containsNode(e, true);"
50 "}"
51 "function attributeStr(e, a) {"
52 " return e.getAttribute(a) || '';"
53 "}"
54 "var res = {"
55 " baseUrl: document.baseURI,"
56 " alternateText: e.getAttribute('alt'),"
57 " boundingRect: '',"
58 " imageUrl: '',"
59 " contentEditable: isEditableElement(e),"
60 " contentSelected: isSelected(e),"
61 " linkTitle: '',"
62 " linkUrl: '',"
63 " mediaUrl: '',"
64 " tagName: e.tagName.toLowerCase()"
65 "};"
66 "var r = e.getBoundingClientRect();"
67 "res.boundingRect = [r.top, r.left, r.width, r.height];"
68 "if (e.tagName.toLowerCase() == 'img')"
69 " res.imageUrl = attributeStr(e, 'src').trim();"
70 "if (e.tagName.toLowerCase() == 'a') {"
71 " res.linkTitle = e.text;"
72 " res.linkUrl = attributeStr(e, 'href').trim();"
73 "}"
74 "while (e) {"
75 " if (res.linkTitle == '' && e.tagName.toLowerCase() == 'a')"
76 " res.linkTitle = e.text;"
77 " if (res.linkUrl == '' && e.tagName.toLowerCase() == 'a')"
78 " res.linkUrl = attributeStr(e, 'href').trim();"
79 " if (res.mediaUrl == '' && isMediaElement(e)) {"
80 " res.mediaUrl = e.currentSrc;"
81 " res.mediaPaused = e.paused;"
82 " res.mediaMuted = e.muted;"
83 " }"
84 " e = e.parentElement;"
85 "}"
86 "return res;"
87 "})()");
88
89 auto *p = const_cast<WebPage*>(page);
90 m_viewportPos = p->mapToViewport(m_pos);
91 const QString &js = source.arg(m_viewportPos.x()).arg(m_viewportPos.y());
92 init(p->url(), p->execJavaScript(js, WebPage::SafeJsWorld).toMap());
93}
94
95void WebHitTestResult::updateWithContextMenuData(const QWebEngineContextMenuRequest &data)
96{
97 if (data.position() != m_pos) {
98 return;
99 }
100
101 m_linkTitle = data.linkText();
102 m_linkUrl = data.linkUrl();
103 m_isContentEditable = data.isContentEditable();
104 m_isContentSelected = !data.selectedText().isEmpty();
105
106 switch (data.mediaType()) {
107 case QWebEngineContextMenuRequest::MediaTypeImage:
108 m_imageUrl = data.mediaUrl();
109 break;
110
111 case QWebEngineContextMenuRequest::MediaTypeVideo:
112 case QWebEngineContextMenuRequest::MediaTypeAudio:
113 m_mediaUrl = data.mediaUrl();
114 break;
115
116 default:
117 break;
118 }
119}
120
122{
123 return m_baseUrl;
124}
125
127{
128 return m_alternateText;
129}
130
132{
133 return m_boundingRect;
134}
135
137{
138 return m_imageUrl;
139}
140
142{
143 return m_isContentEditable;
144}
145
147{
148 return m_isContentSelected;
149}
150
152{
153 return m_isNull;
154}
155
157{
158 return m_linkTitle;
159}
160
162{
163 return m_linkUrl;
164}
165
167{
168 return m_mediaUrl;
169}
170
172{
173 return m_mediaPaused;
174}
175
177{
178 return m_mediaMuted;
179}
180
182{
183 return m_pos;
184}
185
187{
188 return m_viewportPos;
189}
190
192{
193 return m_tagName;
194}
195
196void WebHitTestResult::init(const QUrl &url, const QVariantMap &map)
197{
198 if (map.isEmpty())
199 return;
200
201 m_isNull = false;
202 m_baseUrl = map.value(QSL("baseUrl")).toUrl();
203 m_alternateText = map.value(QSL("alternateText")).toString();
204 m_imageUrl = map.value(QSL("imageUrl")).toUrl();
205 m_isContentEditable = map.value(QSL("contentEditable")).toBool();
206 m_isContentSelected = map.value(QSL("contentSelected")).toBool();
207 m_linkTitle = map.value(QSL("linkTitle")).toString();
208 m_linkUrl = map.value(QSL("linkUrl")).toUrl();
209 m_mediaUrl = map.value(QSL("mediaUrl")).toUrl();
210 m_mediaPaused = map.value(QSL("mediaPaused")).toBool();
211 m_mediaMuted = map.value(QSL("mediaMuted")).toBool();
212 m_tagName = map.value(QSL("tagName")).toString();
213
214 const QVariantList &rect = map.value(QSL("boundingRect")).toList();
215 if (rect.size() == 4)
216 m_boundingRect = QRect(rect.at(0).toInt(), rect.at(1).toInt(), rect.at(2).toInt(), rect.at(3).toInt());
217
218 if (!m_imageUrl.isEmpty())
219 m_imageUrl = url.resolved(m_imageUrl);
220 if (!m_linkUrl.isEmpty())
221 m_linkUrl = m_baseUrl.resolved(m_linkUrl);
222 if (!m_mediaUrl.isEmpty())
223 m_mediaUrl = url.resolved(m_mediaUrl);
224}
QPointF viewportPos() const
QRect boundingRect() const
QString linkTitle() const
bool isContentSelected() const
WebHitTestResult(const WebPage *page, const QPoint &pos)
void updateWithContextMenuData(const QWebEngineContextMenuRequest &data)
QPoint pos() const
bool mediaPaused() const
bool mediaMuted() const
QString alternateText() const
QString tagName() const
bool isContentEditable() const
@ SafeJsWorld
Definition: webpage.h:45
#define QL1S(x)
Definition: qzcommon.h:44
#define QSL(x)
Definition: qzcommon.h:40