18html {
19 display: block;
20 position: relative;
21}
22
23head {
24 display: none
25}
26
27meta {
28 display: none
29}
30
31title {
32 display: none
33}
34
35link {
36 display: none
37}
38
39style {
40 display: none
41}
42
43script {
44 display: none
45}
46
47body {
48 display:block;
49 margin:8px;
50}
51
52p {
53 display:block;
54 margin-top:1em;
55 margin-bottom:1em;
56}
57
58b, strong {
59 display:inline;
60 font-weight:bold;
61}
62
63i, em, cite {
64 display:inline;
65 font-style:italic;
66}
67
68ins, u {
69 text-decoration:underline
70}
71
72del, s, strike {
73 text-decoration:line-through
74}
75
76center
77{
78 text-align:center;
79 display:block;
80}
81
82a:link
83{
84 text-decoration: underline;
85 color: #00f;
86 cursor: pointer;
87}
88
89h1, h2, h3, h4, h5, h6, div {
90 display:block;
91}
92
93h1 {
94 font-weight:bold;
95 margin-top:0.67em;
96 margin-bottom:0.67em;
97 font-size: 2em;
98}
99
100h2 {
101 font-weight:bold;
102 margin-top:0.83em;
103 margin-bottom:0.83em;
104 font-size: 1.5em;
105}
106
107h3 {
108 font-weight:bold;
109 margin-top:1em;
110 margin-bottom:1em;
111 font-size:1.17em;
112}
113
114h4 {
115 font-weight:bold;
116 margin-top:1.33em;
117 margin-bottom:1.33em
118}
119
120h5 {
121 font-weight:bold;
122 margin-top:1.67em;
123 margin-bottom:1.67em;
124 font-size:.83em;
125}
126
127h6 {
128 font-weight:bold;
129 margin-top:2.33em;
130 margin-bottom:2.33em;
131 font-size:.67em;
132}
133
134br {
135 display:inline-block;
136}
137
138br[clear="all"]
139{
140 clear:both;
141}
142
143br[clear="left"]
144{
145 clear:left;
146}
147
148br[clear="right"]
149{
150 clear:right;
151}
152
153span {
154 display:inline
155}
156
157img {
158 display: inline-block;
159}
160
161img[align="right"]
162{
163 float: right;
164}
165
166img[align="left"]
167{
168 float: left;
169}
170
171hr {
172 display: block;
173 margin-top: 0.5em;
174 margin-bottom: 0.5em;
175 margin-left: auto;
176 margin-right: auto;
177 border-style: inset;
178 border-width: 1px
179}
180
181
182/***************** TABLES ********************/
183
184table {
185 display: table;
186 border-collapse: separate;
187 border-spacing: 2px;
188 border-top-color:gray;
189 border-left-color:gray;
190 border-bottom-color:black;
191 border-right-color:black;
192 font-size: medium;
193 font-weight: normal;
194 font-style: normal;
195}
196
197tbody, tfoot, thead {
198 display:table-row-group;
199 vertical-align:middle;
200}
201
202tr {
203 display: table-row;
204 vertical-align: inherit;
205 border-color: inherit;
206}
207
208td, th {
209 display: table-cell;
210 vertical-align: inherit;
211 border-width:1px;
212 padding:1px;
213}
214
215th {
216 font-weight: bold;
217}
218
219table[border] {
220 border-style:solid;
221}
222
223table[border|=0] {
224 border-style:none;
225}
226
227table[border] td, table[border] th {
228 border-style:solid;
229 border-top-color:black;
230 border-left-color:black;
231 border-bottom-color:gray;
232 border-right-color:gray;
233}
234
235table[border|=0] td, table[border|=0] th {
236 border-style:none;
237}
238
239table[align=left] {
240 float: left;
241}
242
243table[align=right] {
244 float: right;
245}
246
247table[align=center] {
248 margin-left: auto;
249 margin-right: auto;
250}
251
252caption {
253 display: table-caption;
254}
255
256td[nowrap], th[nowrap] {
257 white-space:nowrap;
258}
259
260tt, code, kbd, samp {
261 font-family: monospace
262}
263
264pre, xmp, plaintext, listing {
265 display: block;
266 font-family: monospace;
267 white-space: pre;
268 margin: 1em 0
269}
270
271/***************** LISTS ********************/
272
273ul, menu, dir {
274 display: block;
275 list-style-type: disc;
276 margin-top: 1em;
277 margin-bottom: 1em;
278 margin-left: 0;
279 margin-right: 0;
280 padding-left: 40px
281}
282
283ol {
284 display: block;
285 list-style-type: decimal;
286 margin-top: 1em;
287 margin-bottom: 1em;
288 margin-left: 0;
289 margin-right: 0;
290 padding-left: 40px
291}
292
293li {
294 display: list-item;
295}
296
297ul ul, ol ul {
298 list-style-type: circle;
299}
300
301ol ol ul, ol ul ul, ul ol ul, ul ul ul {
302 list-style-type: square;
303}
304
305dd {
306 display: block;
307 margin-left: 40px;
308}
309
310dl {
311 display: block;
312 margin-top: 1em;
313 margin-bottom: 1em;
314 margin-left: 0;
315 margin-right: 0;
316}
317
318dt {
319 display: block;
320}
321
322ol ul, ul ol, ul ul, ol ol {
323 margin-top: 0;
324 margin-bottom: 0
325}
326
327blockquote {
328 display: block;
329 margin-top: 1em;
330 margin-bottom: 1em;
331 margin-left: 40px;
332 margin-right: 40px;
333}
334
335/*********** FORM ELEMENTS ************/
336
337form {
338 display: block;
339 margin-top: 0em;
340}
341
342option {
343 display: none;
344}
345
346input, textarea, keygen, select, button, isindex {
347 margin: 0em;
348 color: initial;
349 line-height: normal;
350 text-transform: none;
351 text-indent: 0;
352 text-shadow: none;
353 display: inline-block;
354}
355input[type="hidden"] {
356 display: none;
357}
358
359
360article, aside, footer, header, hgroup, nav, section
361{
362 display: block;
363}
364
365sub {
366 vertical-align: sub;
367 font-size: smaller;
368}
369
370sup {
371 vertical-align: super;
372 font-size: smaller;
373}
374
375figure {
376 display: block;
377 margin-top: 1em;
378 margin-bottom: 1em;
379 margin-left: 40px;
380 margin-right: 40px;
381}
382
383figcaption {
384 display: block;
385}
386
387)##";
400QLiteHtmlWidget::QLiteHtmlWidget(QWidget *parent)
401 : QAbstractScrollArea(parent)
402 , d(
new QLiteHtmlWidgetPrivate)
404 setMouseTracking(
true);
405 horizontalScrollBar()->setSingleStep(kScrollBarStep);
406 verticalScrollBar()->setSingleStep(kScrollBarStep);
408 d->documentContainer.setCursorCallback([
this](
const QCursor &c) { viewport()->setCursor(c); });
409 d->documentContainer.setPaletteCallback([
this] {
return palette(); });
410 d->documentContainer.setLinkCallback([
this](
const QUrl &url) {
412 if (url.isRelative() && url.path(QUrl::FullyEncoded).isEmpty()) {
414 fullUrl.setFragment(url.fragment(QUrl::FullyEncoded));
417 QMetaObject::invokeMethod(
this, [
this, fullUrl] { emit linkClicked(fullUrl); },
418 Qt::QueuedConnection);
420 d->documentContainer.setClipboardCallback([
this](
bool yes) { emit copyAvailable(yes); });
423 d->context.setMasterStyleSheet(master_css);
426QLiteHtmlWidget::~QLiteHtmlWidget()
431void QLiteHtmlWidget::setUrl(
const QUrl &url)
435 baseUrl.setFragment({});
436 const QString path = baseUrl.path(QUrl::FullyEncoded);
437 const int lastSlash = path.lastIndexOf(
'/');
438 const QString basePath = lastSlash >= 0 ? path.left(lastSlash) : QString();
439 baseUrl.setPath(basePath);
440 d->documentContainer.setBaseUrl(baseUrl.toString(QUrl::FullyEncoded));
441 QMetaObject::invokeMethod(
this, [
this] { updateHightlightedLink(); },
442 Qt::QueuedConnection);
445QUrl QLiteHtmlWidget::url()
const
450void QLiteHtmlWidget::setHtml(
const QString &content)
453 d->documentContainer.setPaintDevice(viewport());
454 d->documentContainer.setDocument(content.toUtf8(), &d->context);
455 verticalScrollBar()->setValue(0);
456 horizontalScrollBar()->setValue(0);
458 QMetaObject::invokeMethod(
this, [
this] { updateHightlightedLink(); },
459 Qt::QueuedConnection);
462QString QLiteHtmlWidget::html()
const
467QString QLiteHtmlWidget::title()
const
469 return d->documentContainer.caption();
472void QLiteHtmlWidget::setZoomFactor(qreal scale)
474 Q_ASSERT(scale != 0);
475 d->zoomFactor = scale;
476 withFixedTextPosition([
this] { render(); });
479qreal QLiteHtmlWidget::zoomFactor()
const
481 return d->zoomFactor;
484bool QLiteHtmlWidget::findText(
const QString &text,
485 QTextDocument::FindFlags flags,
489 bool success =
false;
490 QVector<QRect> oldSelection;
491 QVector<QRect> newSelection;
493 .findText(text, flags, incremental, wrapped, &success, &oldSelection, &newSelection);
495 QRect newSelectionCombined;
496 for (
const QRect &r : std::as_const(newSelection))
497 newSelectionCombined = newSelectionCombined.united(r);
498 QScrollBar *vBar = verticalScrollBar();
499 const int top = newSelectionCombined.top();
500 const int bottom = newSelectionCombined.bottom() - toVirtual(viewport()->size()).height();
501 if (success && top < vBar->value() && vBar->minimum() <= top) {
503 }
else if (success && vBar->value() < bottom && bottom <= vBar->maximum()) {
504 vBar->setValue(bottom);
506 viewport()->update(fromVirtual(newSelectionCombined.translated(-scrollPosition())));
507 for (
const QRect &r : std::as_const(oldSelection))
508 viewport()->update(fromVirtual(r.translated(-scrollPosition())));
513void QLiteHtmlWidget::setDefaultFont(
const QFont &font)
515 withFixedTextPosition([
this, &font] {
516 d->documentContainer.setDefaultFont(font);
521QFont QLiteHtmlWidget::defaultFont()
const
523 return d->documentContainer.defaultFont();
526void QLiteHtmlWidget::setAntialias(
bool on)
528 withFixedTextPosition([
this, on] {
529 d->documentContainer.setAntialias(on);
535void QLiteHtmlWidget::scrollToAnchor(
const QString &name)
537 if (!d->documentContainer.hasDocument())
539 horizontalScrollBar()->setValue(0);
540 if (name.isEmpty()) {
541 verticalScrollBar()->setValue(0);
544 const int y = d->documentContainer.anchorY(name);
546 verticalScrollBar()->setValue(std::min(y, verticalScrollBar()->maximum()));
549void QLiteHtmlWidget::setResourceHandler(
const QLiteHtmlWidget::ResourceHandler &handler)
551 d->documentContainer.setDataCallback(handler);
554QString QLiteHtmlWidget::selectedText()
const
556 return d->documentContainer.selectedText();
559void QLiteHtmlWidget::paintEvent(QPaintEvent *event)
561 if (!d->documentContainer.hasDocument())
563 d->documentContainer.setScrollPosition(scrollPosition());
564 QPainter p(viewport());
565 p.setWorldTransform(QTransform().scale(d->zoomFactor, d->zoomFactor));
566 p.setRenderHint(QPainter::SmoothPixmapTransform,
true);
567 p.setRenderHint(QPainter::Antialiasing,
true);
568 d->documentContainer.draw(&p, toVirtual(event->rect()));
571void QLiteHtmlWidget::resizeEvent(QResizeEvent *event)
573 withFixedTextPosition([
this, event] {
574 QAbstractScrollArea::resizeEvent(event);
579void QLiteHtmlWidget::mouseMoveEvent(QMouseEvent *event)
583 htmlPos(event->pos(), &viewportPos, &pos);
584 const QVector<QRect> areas = d->documentContainer.mouseMoveEvent(pos, viewportPos);
585 for (
const QRect &r : areas)
586 viewport()->update(fromVirtual(r.translated(-scrollPosition())));
588 updateHightlightedLink();
591void QLiteHtmlWidget::mousePressEvent(QMouseEvent *event)
595 htmlPos(event->pos(), &viewportPos, &pos);
596 const QVector<QRect> areas = d->documentContainer.mousePressEvent(pos, viewportPos, event->button());
597 for (
const QRect &r : areas)
598 viewport()->update(fromVirtual(r.translated(-scrollPosition())));
601void QLiteHtmlWidget::mouseReleaseEvent(QMouseEvent *event)
605 htmlPos(event->pos(), &viewportPos, &pos);
606 const QVector<QRect> areas = d->documentContainer.mouseReleaseEvent(pos, viewportPos, event->button());
607 for (
const QRect &r : areas)
608 viewport()->update(fromVirtual(r.translated(-scrollPosition())));
611void QLiteHtmlWidget::mouseDoubleClickEvent(QMouseEvent *event)
615 htmlPos(event->pos(), &viewportPos, &pos);
616 const QVector<QRect> areas = d->documentContainer.mouseDoubleClickEvent(pos, viewportPos, event->button());
617 for (
const QRect &r : areas) {
618 viewport()->update(fromVirtual(r.translated(-scrollPosition())));
622void QLiteHtmlWidget::leaveEvent(QEvent *event)
625 const QVector<QRect> areas = d->documentContainer.leaveEvent();
626 for (
const QRect &r : areas)
627 viewport()->update(fromVirtual(r.translated(-scrollPosition())));
628 setHightlightedLink(QUrl());
631void QLiteHtmlWidget::contextMenuEvent(QContextMenuEvent *event)
635 htmlPos(event->pos(), &viewportPos, &pos);
636 emit contextMenuRequested(event->pos(), d->documentContainer.linkAt(pos, viewportPos));
641 if (key == Qt::Key_Home)
642 return QAbstractSlider::SliderToMinimum;
643 if (key == Qt::Key_End)
644 return QAbstractSlider::SliderToMaximum;
645 if (key == Qt::Key_PageUp)
646 return QAbstractSlider::SliderPageStepSub;
647 if (key == Qt::Key_PageDown)
648 return QAbstractSlider::SliderPageStepAdd;
649 return QAbstractSlider::SliderNoAction;
652void QLiteHtmlWidget::keyPressEvent(QKeyEvent *event)
654 if (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::KeypadModifier) {
655 const QAbstractSlider::SliderAction sliderAction = getSliderAction(event->key());
656 if (sliderAction != QAbstractSlider::SliderNoAction) {
657 verticalScrollBar()->triggerAction(sliderAction);
663 QAbstractScrollArea::keyPressEvent(event);
666void QLiteHtmlWidget::updateHightlightedLink()
670 htmlPos(mapFromGlobal(QCursor::pos()), &viewportPos, &pos);
671 setHightlightedLink(d->documentContainer.linkAt(pos, viewportPos));
674void QLiteHtmlWidget::setHightlightedLink(
const QUrl &url)
676 if (d->lastHighlightedLink == url)
678 d->lastHighlightedLink = url;
679 emit linkHighlighted(d->lastHighlightedLink);
682void QLiteHtmlWidget::withFixedTextPosition(
const std::function<
void()> &action)
687 htmlPos({}, &viewportPos, &pos);
688 const int y = d->documentContainer.withFixedElementPosition(pos.y(), action);
690 verticalScrollBar()->setValue(std::min(y, verticalScrollBar()->maximum()));
693void QLiteHtmlWidget::render()
695 if (!d->documentContainer.hasDocument())
697 const int fullWidth = width() / d->zoomFactor;
698 const QSize vViewportSize = toVirtual(viewport()->size());
699 const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent,
nullptr,
this);
700 const int w = fullWidth - scrollbarWidth - 2;
701 d->documentContainer.render(w, vViewportSize.height());
703 horizontalScrollBar()->setPageStep(vViewportSize.width());
704 horizontalScrollBar()->setRange(0, std::max(0, d->documentContainer.documentWidth() - w));
705 verticalScrollBar()->setPageStep(vViewportSize.height());
707 ->setRange(0, std::max(0, d->documentContainer.documentHeight() - vViewportSize.height()));
708 viewport()->update();
711QPoint QLiteHtmlWidget::scrollPosition()
const
713 return {horizontalScrollBar()->value(), verticalScrollBar()->value()};
716void QLiteHtmlWidget::htmlPos(
const QPoint &pos, QPoint *viewportPos, QPoint *htmlPos)
const
718 *viewportPos = toVirtual(viewport()->mapFromParent(pos));
719 *htmlPos = *viewportPos + scrollPosition();
722QPoint QLiteHtmlWidget::toVirtual(
const QPoint &p)
const
724 return {
int(p.x() / d->zoomFactor),
int(p.y() / d->zoomFactor)};
727QSize QLiteHtmlWidget::toVirtual(
const QSize &s)
const
729 return {
int(s.width() / d->zoomFactor),
int(s.height() / d->zoomFactor)};
732QRect QLiteHtmlWidget::toVirtual(
const QRect &r)
const
734 return {toVirtual(r.topLeft()), toVirtual(r.size())};
737QRect QLiteHtmlWidget::fromVirtual(
const QRect &r)
const
739 const QPoint tl{
int(r.x() * d->zoomFactor),
int(r.y() * d->zoomFactor)};
741 const QSize s{
int(r.width() * d->zoomFactor + 0.5) + 1,
742 int(r.height() * d->zoomFactor + 0.5) + 1};