16
|
1 |
|
|
2 |
#include "TiledWebView.h"
|
|
3 |
|
|
4 |
#include <QPainter>
|
|
5 |
#include <QPixmap>
|
|
6 |
#include <QStyleOptionGraphicsItem>
|
|
7 |
#include <QWebFrame>
|
|
8 |
#include <QApplication>
|
|
9 |
#include <QGraphicsView>
|
|
10 |
#include <QGraphicsSceneResizeEvent>
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
const int cTileSize = 64;
|
|
15 |
const qreal cBigSideTileOverHead = 2;
|
|
16 |
const qreal cSmallSideTileOverHead = 2.5;
|
|
17 |
const int cTileUpdateTimerTick = 50;
|
|
18 |
const int cPaintIdleTimeout = cTileUpdateTimerTick * 2;
|
|
19 |
const int cTileRectRecenterTimeout = 500;
|
|
20 |
const int cTileScaleUpdateTimeout = 250;
|
|
21 |
const int cIdleTileUpdateChunkSize = 4;
|
|
22 |
const int cInPaintTileUpdateTimeout = 18;
|
|
23 |
|
|
24 |
|
|
25 |
TiledWebView::TiledWebView(QGraphicsItem* parent) : QGraphicsWebView(parent)
|
|
26 |
{
|
|
27 |
m_tilesPool.clear();
|
|
28 |
m_tilesField = 0;
|
|
29 |
m_inUpdate = false;
|
|
30 |
m_tilesRectCentered = false;
|
|
31 |
m_tilesFrozen = false;
|
|
32 |
m_needViewportTilesUpdate = false;
|
|
33 |
m_needScaleCommit = false;
|
|
34 |
m_needTilesFieldRebuild = false;
|
|
35 |
m_lastScrollDelta = QPoint(0, 0);
|
|
36 |
#ifdef USE_ASSISTANT_ITEM
|
|
37 |
m_assistant = new TiledWebViewAssistant();
|
|
38 |
m_assistant->setParentItem(this);
|
|
39 |
m_assistant->m_master = this;
|
|
40 |
|
|
41 |
setFlag(QGraphicsItem::ItemHasNoContents, true);
|
|
42 |
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
|
43 |
#endif
|
|
44 |
|
|
45 |
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTimeout()));
|
|
46 |
connect(this, SIGNAL(scaleChanged()), this, SLOT(scheduleScaleUpdate()));
|
|
47 |
m_userPaintTS.start();
|
|
48 |
|
|
49 |
}
|
|
50 |
|
|
51 |
TiledWebView::~TiledWebView()
|
|
52 |
{
|
|
53 |
delete[] m_tilesField;
|
|
54 |
m_tilesField = 0;
|
|
55 |
for(int i = 0; i < m_tilesPool.count(); i++) {
|
|
56 |
delete m_tilesPool[i];
|
|
57 |
m_tilesPool[i] = 0;
|
|
58 |
}
|
|
59 |
}
|
|
60 |
|
|
61 |
void TiledWebView::loadStarted()
|
|
62 |
{
|
|
63 |
// resetTiles(QRect(QPoint(0, 0), m_tilesDim), false);
|
|
64 |
m_needViewportTilesUpdate = true;
|
|
65 |
|
|
66 |
startUpdateTimer();
|
|
67 |
}
|
|
68 |
|
|
69 |
void TiledWebView::setPage(QWebPage* page)
|
|
70 |
{
|
|
71 |
bool doneOnce = false;
|
|
72 |
|
|
73 |
if(!doneOnce) {
|
|
74 |
doneOnce = true;
|
|
75 |
page->setProperty("_q_RepaintThrottlingPreset", QVariant::fromValue(QString("Medium")));
|
|
76 |
}
|
|
77 |
|
|
78 |
page->setProperty("_q_HTMLTokenizerChunkSize", 1024);
|
|
79 |
page->setProperty("_q_HTMLTokenizerTimeDelay", 0.750);
|
|
80 |
resetTiles(QRect(QPoint(0, 0), m_tilesDim), false);
|
|
81 |
m_needViewportTilesUpdate = true;
|
|
82 |
|
|
83 |
QGraphicsWebView::setPage(page);
|
|
84 |
|
|
85 |
QPalette pal = palette();
|
|
86 |
pal.setColor(QPalette::ButtonText,Qt::black);
|
|
87 |
pal.setBrush(QPalette::Base, Qt::white);
|
|
88 |
setPalette(pal);
|
|
89 |
page->setPalette(pal);
|
|
90 |
|
|
91 |
connect(page, SIGNAL(repaintRequested(QRect)), this, SLOT(repaintRequested(QRect)));
|
|
92 |
connect(page, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
|
|
93 |
m_needViewportTilesUpdate = true;
|
|
94 |
startUpdateTimer();
|
|
95 |
}
|
|
96 |
|
|
97 |
//#define TILEPOOL_DEBUG
|
|
98 |
TiledWebView::Tile::Tile() : img(cTileSize,cTileSize), ready(0), used(0)
|
|
99 |
{
|
|
100 |
}
|
|
101 |
|
|
102 |
TiledWebView::Tile* TiledWebView::tileAt(const QPoint& p) const
|
|
103 |
{
|
|
104 |
Q_ASSERT(p.x() < m_tilesDim.width() && p.y() < m_tilesDim.height());
|
|
105 |
Q_ASSERT(m_tilesField);
|
|
106 |
|
|
107 |
return m_tilesField[m_tilesDim.width() * p.y() + p.x()];
|
|
108 |
}
|
|
109 |
|
|
110 |
void TiledWebView::setTileAt(const QPoint& p,Tile* t)
|
|
111 |
{
|
|
112 |
m_tilesField[m_tilesDim.width() * p.y() + p.x()] = t;
|
|
113 |
}
|
|
114 |
|
|
115 |
static void boundPoint(const QPoint& min, QPoint& p, const QPoint &max)
|
|
116 |
{
|
|
117 |
p.setX(qBound(min.x(),p.x(),max.x()));
|
|
118 |
p.setY(qBound(min.y(),p.y(),max.y()));
|
|
119 |
}
|
|
120 |
|
|
121 |
static QPoint topPoint(const QSize& s)
|
|
122 |
{
|
|
123 |
return QPoint(s.width() - 1, s.height() - 1);
|
|
124 |
}
|
|
125 |
|
|
126 |
TiledWebView::Tile* TiledWebView::createTile(const QPoint& p)
|
|
127 |
{
|
|
128 |
int i;
|
|
129 |
for(i = 0; i < m_tilesPool.count(); i++)
|
|
130 |
if(!m_tilesPool[i] || !m_tilesPool[i]->used)
|
|
131 |
break;
|
|
132 |
|
|
133 |
Tile* ret;
|
|
134 |
if(i < m_tilesPool.count()) {
|
|
135 |
if(!m_tilesPool[i]) {
|
|
136 |
m_tilesPool[i] = new Tile();
|
|
137 |
}
|
|
138 |
setTileAt(p, m_tilesPool[i]);
|
|
139 |
ret = m_tilesPool[i];
|
|
140 |
} else {
|
|
141 |
ret = new Tile();
|
|
142 |
m_tilesPool.append(ret);
|
|
143 |
setTileAt(p, ret);
|
|
144 |
}
|
|
145 |
|
|
146 |
ret->used = true;
|
|
147 |
|
|
148 |
#ifdef TILEPOOL_DEBUG
|
|
149 |
checkTilesField();
|
|
150 |
#endif
|
|
151 |
return ret;
|
|
152 |
}
|
|
153 |
|
|
154 |
QPoint TiledWebView::tileAtPoint(const QPointF& p) const
|
|
155 |
{
|
|
156 |
QPointF tmp = mapToTileCoords(p - m_tilesRect.topLeft());
|
|
157 |
tmp /= cTileSize;
|
|
158 |
QPoint ret((int)tmp.x(),(int)tmp.y());
|
|
159 |
return ret;
|
|
160 |
}
|
|
161 |
|
|
162 |
QRectF TiledWebView::tileRect(const QPoint& t) const
|
|
163 |
{
|
|
164 |
QRectF tRect = mapToTileCoords(m_tilesRect);
|
|
165 |
QRectF ret(tRect.topLeft() + t * cTileSize,QSizeF(cTileSize,cTileSize));
|
|
166 |
|
|
167 |
return ret;
|
|
168 |
}
|
|
169 |
|
|
170 |
static int calcD(const QPoint p1, QPoint p2)
|
|
171 |
{
|
|
172 |
int d1 = p2.x() - p1.x();
|
|
173 |
int d2 = p2.y() - p1.y();
|
|
174 |
return d1 * d1 + d2 * d2;
|
|
175 |
}
|
|
176 |
QRectF TiledWebView::viewPortRect() const
|
|
177 |
{
|
|
178 |
return mapRectFromParent(QRectF(QPointF(0, 0),static_cast<QGraphicsWidget*>(parentItem())->size()));
|
|
179 |
}
|
|
180 |
|
|
181 |
void TiledWebView::boundTile(QPoint& t) const
|
|
182 |
{
|
|
183 |
boundPoint(QPoint(0,0),t,topPoint(m_tilesDim));
|
|
184 |
}
|
|
185 |
|
|
186 |
QPoint TiledWebView::findTile4Update(bool inView, bool addDirty) const
|
|
187 |
{
|
|
188 |
QRectF vpRect = viewPortRect();
|
|
189 |
QRectF updateRect = m_tilesRect;
|
|
190 |
if(inView)
|
|
191 |
updateRect = updateRect.intersect(vpRect);
|
|
192 |
QPoint found(-1, -1);
|
|
193 |
if(updateRect.isEmpty()) return found;
|
|
194 |
|
|
195 |
QPoint topLeft = tileAtPoint(updateRect.topLeft());
|
|
196 |
QPoint bottomRight = tileAtPoint(updateRect.bottomRight());
|
|
197 |
QPoint center = tileAtPoint(vpRect.center());
|
|
198 |
|
|
199 |
bottomRight += QPoint(1, 1);
|
|
200 |
boundTile(topLeft);
|
|
201 |
boundTile(bottomRight);
|
|
202 |
boundPoint(topLeft,center,bottomRight);
|
|
203 |
|
|
204 |
int d = 1000000; // just big enough value;
|
|
205 |
int tmpD;
|
|
206 |
for(int j = topLeft.y(); j <= bottomRight.y(); j++)
|
|
207 |
for(int i = topLeft.x(); i <= bottomRight.x(); i++) {
|
|
208 |
QPoint p(i,j);
|
|
209 |
Tile* t = tileAt(p);
|
|
210 |
if(!t || !t->ready || (addDirty && !t->dirtyRect.isEmpty())) {
|
|
211 |
tmpD = calcD(center, p);
|
|
212 |
if(tmpD < d) {
|
|
213 |
d = tmpD;
|
|
214 |
found = p;
|
|
215 |
}
|
|
216 |
}
|
|
217 |
}
|
|
218 |
|
|
219 |
return found;
|
|
220 |
}
|
|
221 |
|
|
222 |
QList<QPoint> TiledWebView::findTileLine4Update(bool dirty, bool inView, bool useScrollDirection) const
|
|
223 |
{
|
|
224 |
QRectF vpRect = viewPortRect();
|
|
225 |
QRectF updateRect = m_tilesRect;
|
|
226 |
if(inView)
|
|
227 |
updateRect = updateRect.intersect(vpRect);
|
|
228 |
QList<QPoint> ret;
|
|
229 |
if(updateRect.isEmpty()) return ret;
|
|
230 |
|
|
231 |
QPoint topLeft = tileAtPoint(updateRect.topLeft());
|
|
232 |
QPoint bottomRight = tileAtPoint(updateRect.bottomRight());
|
|
233 |
QPoint topVPLeft = tileAtPoint(vpRect.topLeft());
|
|
234 |
QPoint bottomVPRight = tileAtPoint(vpRect.bottomRight());
|
|
235 |
QPoint center = tileAtPoint(vpRect.center());
|
|
236 |
|
|
237 |
bottomRight += QPoint(1, 1);
|
|
238 |
bottomVPRight += QPoint(1, 1);
|
|
239 |
boundTile(topLeft);
|
|
240 |
boundTile(bottomRight);
|
|
241 |
boundTile(topVPLeft);
|
|
242 |
boundTile(bottomVPRight);
|
|
243 |
boundPoint(topLeft,center,bottomRight);
|
|
244 |
|
|
245 |
int maxCount = qAbs(topLeft.x() - center.x());
|
|
246 |
maxCount = qMax(maxCount, qAbs(topLeft.y() - center.y()));
|
|
247 |
maxCount = qMax(maxCount, qAbs(bottomRight.x() - center.x()));
|
|
248 |
maxCount = qMax(maxCount, qAbs(bottomRight.y() - center.y()));
|
|
249 |
|
|
250 |
for(int i = 0; i < maxCount; i++) {
|
|
251 |
int j;
|
|
252 |
if((m_lastScrollDelta.y() > 0 || !useScrollDirection) &&
|
|
253 |
center.y() + i <= bottomRight.y())
|
|
254 |
for(j = topVPLeft.x(); j <= bottomVPRight.x(); j++) {
|
|
255 |
QPoint p(j, center.y() + i);
|
|
256 |
Tile* t = tileAt(p);
|
|
257 |
if(!t || !t->ready || (dirty && !t->dirtyRect.isEmpty())) {
|
|
258 |
ret += p;
|
|
259 |
}
|
|
260 |
}
|
|
261 |
if(!ret.isEmpty())
|
|
262 |
break;
|
|
263 |
|
|
264 |
if((m_lastScrollDelta.y() < 0 || !useScrollDirection) &&
|
|
265 |
center.y() - i >= topLeft.y())
|
|
266 |
for(j = topVPLeft.x(); j <= bottomVPRight.x(); j++) {
|
|
267 |
QPoint p(j, center.y() - i);
|
|
268 |
Tile* t = tileAt(p);
|
|
269 |
if(!t || !t->ready || (dirty && !t->dirtyRect.isEmpty())) {
|
|
270 |
ret += p;
|
|
271 |
}
|
|
272 |
}
|
|
273 |
if(!ret.isEmpty())
|
|
274 |
break;
|
|
275 |
|
|
276 |
if((m_lastScrollDelta.x() > 0 || !useScrollDirection) &&
|
|
277 |
center.x() + i <= bottomRight.x())
|
|
278 |
for(j = topVPLeft.y(); j <= bottomVPRight.y(); j++) {
|
|
279 |
QPoint p(center.x() + i, j);
|
|
280 |
Tile* t = tileAt(p);
|
|
281 |
if(!t || !t->ready || (dirty && !t->dirtyRect.isEmpty())) {
|
|
282 |
ret += p;
|
|
283 |
}
|
|
284 |
}
|
|
285 |
if(!ret.isEmpty())
|
|
286 |
break;
|
|
287 |
|
|
288 |
if((m_lastScrollDelta.x() < 0 || !useScrollDirection) &&
|
|
289 |
center.x() - i >= topLeft.x())
|
|
290 |
for(j = topVPLeft.y(); j <= bottomVPRight.y(); j++) {
|
|
291 |
QPoint p(center.x() - i, j);
|
|
292 |
Tile* t = tileAt(p);
|
|
293 |
if(!t || !t->ready || (dirty && !t->dirtyRect.isEmpty())) {
|
|
294 |
ret += p;
|
|
295 |
}
|
|
296 |
}
|
|
297 |
if(!ret.isEmpty())
|
|
298 |
break;
|
|
299 |
}
|
|
300 |
|
|
301 |
return ret;
|
|
302 |
}
|
|
303 |
|
|
304 |
QRectF TiledWebView::updateTile(const QPoint& t)
|
|
305 |
{
|
|
306 |
m_inUpdate = true;
|
|
307 |
Tile* tile = tileAt(t);
|
|
308 |
if(!tile) tile = createTile(t);
|
|
309 |
|
|
310 |
QPainter p(&(tile->img));
|
|
311 |
QRectF tRect = mapFromTileCoords(tileRect(t));
|
|
312 |
QRectF tDirtyRect = mapFromTileCoords(tile->dirtyRect);
|
|
313 |
QRectF updateRect = !tile->ready || tDirtyRect.isEmpty() ? tRect : tDirtyRect;
|
|
314 |
|
|
315 |
|
|
316 |
//if(!tile->ready)
|
|
317 |
// p.fillRect(0, 0, cTileSize, cTileSize, Qt::white);
|
|
318 |
|
|
319 |
tile->ready = true;
|
|
320 |
tile->dirtyRect = QRectF();
|
|
321 |
|
|
322 |
p.scale(m_tilesScale,m_tilesScale);
|
|
323 |
|
|
324 |
qreal adjust = 2 + m_tilesScale;
|
|
325 |
|
|
326 |
// adjust rect to cover rouding errors
|
|
327 |
updateRect.adjust(-adjust, -adjust, adjust, adjust);
|
|
328 |
|
|
329 |
QRegion clip(updateRect.toRect());
|
|
330 |
p.translate(-tRect.topLeft());
|
|
331 |
p.setClipRegion(clip);
|
|
332 |
// p.fillRect(clip.boundingRect(), Qt::white);
|
|
333 |
|
|
334 |
// p.setRenderHint(QPainter::SmoothPixmapTransform); // cause assert now
|
|
335 |
// p.setRenderHint(QPainter::Antialiasing);
|
|
336 |
|
|
337 |
page()->mainFrame()->render(&p, QWebFrame::ContentsLayer, clip);
|
|
338 |
|
|
339 |
m_inUpdate = false;
|
|
340 |
return updateRect;
|
|
341 |
}
|
|
342 |
|
|
343 |
void TiledWebView::repaintRequested(QRect r)
|
|
344 |
{
|
|
345 |
if(!m_tilesField) return;
|
|
346 |
|
|
347 |
if(r.isEmpty())
|
|
348 |
r = m_tilesRect.adjusted(-1, -1, 1, 1).toRect();
|
|
349 |
|
|
350 |
QPoint topLeftTile = tileAtPoint(r.topLeft());
|
|
351 |
QPoint bottomRightTile = tileAtPoint(r.bottomRight());
|
|
352 |
boundTile(topLeftTile);
|
|
353 |
boundTile(bottomRightTile);
|
|
354 |
QRectF repaintClip = mapToTileCoords(r);
|
|
355 |
bool needUpdate = false;
|
|
356 |
QRectF vpRect = mapToTileCoords(viewPortRect());
|
|
357 |
|
|
358 |
for(int j = topLeftTile.y(); j <= bottomRightTile.y(); j++)
|
|
359 |
for(int i = topLeftTile.x(); i <= bottomRightTile.x(); i++) {
|
|
360 |
QPoint t(i, j);
|
|
361 |
QRectF clip = tileRect(t) & repaintClip;
|
|
362 |
if(!clip.isEmpty()) {
|
|
363 |
|
|
364 |
Tile* tile = tileAt(t);
|
|
365 |
if(tile && tile->ready) {
|
|
366 |
if(!tile->dirtyRect.isEmpty())
|
|
367 |
clip |= tile->dirtyRect;
|
|
368 |
tile->dirtyRect = clip;
|
|
369 |
// if(vpRect.intersects(tile->dirtyRect)) {
|
|
370 |
// m_needViewportTilesUpdate = true;
|
|
371 |
// }
|
|
372 |
}
|
|
373 |
needUpdate = true;
|
|
374 |
}
|
|
375 |
}
|
|
376 |
|
|
377 |
if(needUpdate)
|
|
378 |
startUpdateTimer();
|
|
379 |
|
|
380 |
}
|
|
381 |
|
|
382 |
QPixmap* TiledWebView::getUnprepPixmap()
|
|
383 |
{
|
|
384 |
static const int squareMult = 1;
|
|
385 |
static const int cellSize = 16;
|
|
386 |
static QPixmap pixmap(squareMult * cellSize, squareMult * cellSize);
|
|
387 |
static bool init = false;
|
|
388 |
|
|
389 |
if(!init) {
|
|
390 |
init = true;
|
|
391 |
QPainter p(&pixmap);
|
|
392 |
p.fillRect(pixmap.rect(),Qt::lightGray);
|
|
393 |
// p.setPen(QColor(182,242,255));
|
|
394 |
// p.setPen(QColor(Qt::darkBlue));
|
|
395 |
p.setPen(Qt::darkGray);
|
|
396 |
for(int i = -1; i < squareMult + 1; i++) {
|
|
397 |
int xoffs = i * cellSize;
|
|
398 |
for(int j = -1; j < squareMult + 1; j++) {
|
|
399 |
int yoffs = j * cellSize;
|
|
400 |
p.drawLine(xoffs + 7, yoffs - 4, xoffs + 7, yoffs + 2);
|
|
401 |
p.drawLine(xoffs + 4, yoffs + 7, xoffs + 10, yoffs + 7);
|
|
402 |
p.drawLine(xoffs + 15, yoffs + 4, xoffs + 15, yoffs + 10);
|
|
403 |
p.drawLine(xoffs + 12, yoffs + 15, xoffs + 18, yoffs + 15);
|
|
404 |
}
|
|
405 |
}
|
|
406 |
}
|
|
407 |
|
|
408 |
return &pixmap;
|
|
409 |
}
|
|
410 |
|
|
411 |
QSize TiledWebView::getTileFieldDim()
|
|
412 |
{
|
|
413 |
QSizeF vpSize = static_cast<QGraphicsWidget*>(parentItem())->size();
|
|
414 |
qreal heightMult = cBigSideTileOverHead;
|
|
415 |
qreal widthMult = cSmallSideTileOverHead;
|
|
416 |
if(vpSize.width() > vpSize.height())
|
|
417 |
qSwap(widthMult, heightMult);
|
|
418 |
return QSize((int)((vpSize.width() * widthMult + cTileSize) / cTileSize),
|
|
419 |
(int)((vpSize.height() * heightMult + cTileSize) / cTileSize));
|
|
420 |
}
|
|
421 |
|
|
422 |
void TiledWebView::createTileField()
|
|
423 |
{
|
|
424 |
QRectF vpRect = viewPortRect();
|
|
425 |
|
|
426 |
m_tilesDim = getTileFieldDim();
|
|
427 |
m_tilesPool.reserve(m_tilesDim.width() * m_tilesDim.height());
|
|
428 |
|
|
429 |
|
|
430 |
m_tilesField = new Tile*[m_tilesDim.width() * m_tilesDim.height()];
|
|
431 |
memset(m_tilesField, 0, sizeof(Tile*) * m_tilesDim.width() * m_tilesDim.height());
|
|
432 |
m_tilesScale = scale();
|
|
433 |
|
|
434 |
adjustTilesToViewPort(true);// mapFromTileCoords(QRectF(QPointF(3, 5) * cTileSize, m_tilesDim * cTileSize));
|
|
435 |
}
|
|
436 |
|
|
437 |
QRectF TiledWebView::validateTileRect(const QRectF& rect, const QSize& dim) const
|
|
438 |
{
|
|
439 |
QRectF ret(rect);
|
|
440 |
QRectF vpRect = viewPortRect();
|
|
441 |
qreal tileSize = cTileSize / m_tilesScale;
|
|
442 |
|
|
443 |
if(ret.bottom() > size().height() + tileSize)
|
|
444 |
ret.moveBottom(size().height() + tileSize);
|
|
445 |
if(ret.top() < 0)
|
|
446 |
ret.moveTop(0);
|
|
447 |
|
|
448 |
if(ret.right() > size().width() + tileSize)
|
|
449 |
ret.moveRight(size().width() + tileSize);
|
|
450 |
if(ret.left() < 0)
|
|
451 |
ret.moveLeft(0);
|
|
452 |
|
|
453 |
if(ret.width() < vpRect.width())
|
|
454 |
ret.setLeft(0);
|
|
455 |
|
|
456 |
if(ret.height() < vpRect.height())
|
|
457 |
ret.setTop(0);
|
|
458 |
|
|
459 |
QPointF p = mapToTileCoords(ret.topLeft());
|
|
460 |
// allign coordinates to tile boundary
|
|
461 |
QPoint pp = (p / cTileSize).toPoint();
|
|
462 |
p = QPointF(pp) * cTileSize;
|
|
463 |
|
|
464 |
return mapFromTileCoords(QRectF(p, dim * cTileSize));
|
|
465 |
}
|
|
466 |
|
|
467 |
QRectF TiledWebView::adjustedTileRect(const QSize& dim) const
|
|
468 |
{
|
|
469 |
QRectF ret(m_tilesRect);
|
|
470 |
if(ret.isEmpty())
|
|
471 |
ret = QRectF(QPoint(0,0),mapFromTileCoords(dim * cTileSize));
|
|
472 |
// no repositioning and scaling and tile dropping during scaling
|
|
473 |
if(!qFuzzyCompare(m_tilesScale,scale()))
|
|
474 |
return ret;
|
|
475 |
|
|
476 |
QRectF vpRect = viewPortRect();
|
|
477 |
qreal tileSize = cTileSize / m_tilesScale;
|
|
478 |
if(vpRect.bottom() > ret.bottom())
|
|
479 |
ret.moveTop(vpRect.top() - tileSize);
|
|
480 |
else if(vpRect.top() < ret.top())
|
|
481 |
ret.moveBottom(vpRect.bottom() + tileSize);
|
|
482 |
|
|
483 |
if(vpRect.right() > ret.right())
|
|
484 |
ret.moveLeft(vpRect.left() - tileSize);
|
|
485 |
else if(vpRect.left() < ret.left())
|
|
486 |
ret.moveRight(vpRect.right() + tileSize);
|
|
487 |
|
|
488 |
return validateTileRect(ret, dim);
|
|
489 |
}
|
|
490 |
|
|
491 |
QRectF TiledWebView::centeredTileRect(const QSize& dim) const
|
|
492 |
{
|
|
493 |
QRectF vpRect = viewPortRect();
|
|
494 |
QSizeF tilesSize = mapFromTileCoords(dim * cTileSize);
|
|
495 |
QPoint centerOffset(tilesSize.width() / 2, tilesSize.height() / 2);
|
|
496 |
QRectF centeredRect(vpRect.center() - centerOffset,tilesSize);
|
|
497 |
|
|
498 |
return validateTileRect(centeredRect, dim);
|
|
499 |
}
|
|
500 |
|
|
501 |
void TiledWebView::adjustTilesToViewPort(bool center)
|
|
502 |
{
|
|
503 |
QRectF newTilesRect = center ? centeredTileRect(m_tilesDim) :
|
|
504 |
adjustedTileRect(m_tilesDim);
|
|
505 |
m_tilesRectCentered = center;
|
|
506 |
|
|
507 |
moveTilesRect(newTilesRect);
|
|
508 |
}
|
|
509 |
|
|
510 |
void TiledWebView::moveTilesRect(const QRectF& newTilesRect)
|
|
511 |
{
|
|
512 |
QRectF trNew = mapToTileCoords(newTilesRect);
|
|
513 |
QRectF trOld = mapToTileCoords(m_tilesRect);
|
|
514 |
|
|
515 |
if(trNew == trOld) return;
|
|
516 |
|
|
517 |
if(trNew.intersects(trOld)) {
|
|
518 |
QPoint trDiff = ((trNew.topLeft() - trOld.topLeft()) / cTileSize).toPoint();
|
|
519 |
scrollTileField(-trDiff);
|
|
520 |
} else {
|
|
521 |
resetTiles(QRect(QPoint(0,0), m_tilesDim), false);
|
|
522 |
#ifdef TILEPOOL_DEBUG
|
|
523 |
checkTilesField();
|
|
524 |
#endif
|
|
525 |
}
|
|
526 |
m_tilesRect = newTilesRect;
|
|
527 |
}
|
|
528 |
|
|
529 |
void TiledWebView::resetTiles(const QRect& r, bool remove)
|
|
530 |
{
|
|
531 |
for(int j = r.top(); j <= r.bottom(); j++)
|
|
532 |
for(int i = r.left(); i <= r.right(); i++) {
|
|
533 |
QPoint t(i, j);
|
|
534 |
Tile* tile = tileAt(t);
|
|
535 |
if(tile) {
|
|
536 |
tile->ready = false;
|
|
537 |
tile->dirtyRect = QRect();
|
|
538 |
if(remove) {
|
|
539 |
tile->used = false;
|
|
540 |
setTileAt(t, 0);
|
|
541 |
}
|
|
542 |
}
|
|
543 |
}
|
|
544 |
}
|
|
545 |
|
|
546 |
void TiledWebView::scrollTileField(const QPoint& diff)
|
|
547 |
{
|
|
548 |
#ifdef TILEPOOL_DEBUG
|
|
549 |
checkTilesField();
|
|
550 |
#endif
|
|
551 |
if(qAbs(diff.x()) > m_tilesDim.width() || qAbs(diff.y()) > m_tilesDim.height())
|
|
552 |
return;
|
|
553 |
|
|
554 |
if(diff.x() > 0) {
|
|
555 |
resetTiles(QRect(QPoint(m_tilesDim.width() - diff.x(),0),
|
|
556 |
QSize(diff.x(), m_tilesDim.height())), true);
|
|
557 |
|
|
558 |
for(int i = m_tilesDim.width() - diff.x() - 1; i >= 0; i--) {
|
|
559 |
int dstNum = i + diff.x();
|
|
560 |
|
|
561 |
for(int j = 0; j < m_tilesDim.height(); j++) {
|
|
562 |
setTileAt(dstNum, j, tileAt(i, j));
|
|
563 |
setTileAt(i, j, 0);
|
|
564 |
}
|
|
565 |
}
|
|
566 |
} else if(diff.x() < 0) {
|
|
567 |
resetTiles(QRect(QPoint(0,0),
|
|
568 |
QSize(-diff.x(), m_tilesDim.height())), true);
|
|
569 |
|
|
570 |
for(int i = -diff.x(); i < m_tilesDim.width(); i++) {
|
|
571 |
int dstNum = i + diff.x();
|
|
572 |
|
|
573 |
for(int j = 0; j < m_tilesDim.height(); j++) {
|
|
574 |
setTileAt(dstNum, j, tileAt(i, j));
|
|
575 |
setTileAt(i, j, 0);
|
|
576 |
}
|
|
577 |
}
|
|
578 |
}
|
|
579 |
|
|
580 |
if(diff.y() > 0) {
|
|
581 |
resetTiles(QRect(QPoint(0, m_tilesDim.height() - diff.y()),
|
|
582 |
QSize(m_tilesDim.width(), diff.y())), true);
|
|
583 |
|
|
584 |
for(int i = m_tilesDim.height() - diff.y() - 1; i >= 0; i--) {
|
|
585 |
int dstNum = i + diff.y();
|
|
586 |
Tile **srcLine = m_tilesField + m_tilesDim.width() * i;
|
|
587 |
Tile **dstLine = m_tilesField + m_tilesDim.width() * dstNum;
|
|
588 |
memcpy(dstLine, srcLine, m_tilesDim.width() * sizeof(Tile*));
|
|
589 |
memset(srcLine, 0, m_tilesDim.width() * sizeof(Tile*));
|
|
590 |
}
|
|
591 |
} else if(diff.y() < 0) {
|
|
592 |
resetTiles(QRect(QPoint(0, 0),
|
|
593 |
QSize(m_tilesDim.width(), -diff.y())), true);
|
|
594 |
|
|
595 |
for(int i = -diff.y(); i < m_tilesDim.height(); i++) {
|
|
596 |
int dstNum = i + diff.y();
|
|
597 |
Tile **srcLine = m_tilesField + m_tilesDim.width() * i;
|
|
598 |
Tile **dstLine = m_tilesField + m_tilesDim.width() * dstNum;
|
|
599 |
memcpy(dstLine, srcLine, m_tilesDim.width() * sizeof(Tile*));
|
|
600 |
memset(srcLine, 0, m_tilesDim.width() * sizeof(Tile*));
|
|
601 |
}
|
|
602 |
}
|
|
603 |
#ifdef TILEPOOL_DEBUG
|
|
604 |
checkTilesField();
|
|
605 |
#endif
|
|
606 |
}
|
|
607 |
|
|
608 |
QList<QRectF> TiledWebView::updateViewportTiles(QList<TileSet> *updatedTiles)
|
|
609 |
{
|
|
610 |
QList<QRectF> ret;
|
|
611 |
// update all visible tiles
|
|
612 |
QRectF vpRect = viewPortRect();
|
|
613 |
|
|
614 |
QPoint topLeft = tileAtPoint(vpRect.topLeft());
|
|
615 |
QPoint bottomRight = tileAtPoint(vpRect.bottomRight());
|
|
616 |
|
|
617 |
bottomRight += QPoint(1, 1);
|
|
618 |
boundTile(topLeft);
|
|
619 |
boundTile(bottomRight);
|
|
620 |
for(int j = topLeft.y(); j <= bottomRight.y(); j++)
|
|
621 |
for(int i = topLeft.x(); i <= bottomRight.x(); i++) {
|
|
622 |
QPoint t(i, j);
|
|
623 |
Tile *tile = tileAt(t);
|
|
624 |
if(!tile || !tile->ready || !tile->dirtyRect.isEmpty()) {
|
|
625 |
QRectF r = updateTile(t);
|
|
626 |
ret += r;
|
|
627 |
if(updatedTiles)
|
|
628 |
*updatedTiles += TileSet(t, r);
|
|
629 |
}
|
|
630 |
}
|
|
631 |
|
|
632 |
m_needViewportTilesUpdate = false;
|
|
633 |
return ret;
|
|
634 |
}
|
|
635 |
|
|
636 |
void TiledWebView::doScaleCommit()
|
|
637 |
{
|
|
638 |
m_needScaleCommit = false;
|
|
639 |
if(qFuzzyCompare(m_tilesScale, scale()))
|
|
640 |
return;
|
|
641 |
|
|
642 |
resetTiles(QRect(QPoint(0,0), m_tilesDim), true);
|
|
643 |
#ifdef TILEPOOL_DEBUG
|
|
644 |
checkTilesField();
|
|
645 |
#endif
|
|
646 |
m_tilesScale = scale();
|
|
647 |
adjustTilesToViewPort(true);
|
|
648 |
m_needViewportTilesUpdate = true;
|
|
649 |
}
|
|
650 |
|
|
651 |
void TiledWebView::commitZoom()
|
|
652 |
{
|
|
653 |
m_needScaleCommit = true;
|
|
654 |
|
|
655 |
startUpdateTimer();
|
|
656 |
}
|
|
657 |
|
|
658 |
QList<QRectF> TiledWebView::updateScrollAreaTilesChunk(QList<TileSet> *updatedTiles, bool inPaint)
|
|
659 |
{
|
|
660 |
QList<QRectF> dirtyRects;
|
|
661 |
QList<QPoint> lst = findTileLine4Update(false, true);
|
|
662 |
if(lst.isEmpty())
|
|
663 |
lst = findTileLine4Update(false, false);
|
|
664 |
if(lst.isEmpty())
|
|
665 |
lst = findTileLine4Update(false, true, false);
|
|
666 |
// if(!inPaint) {
|
|
667 |
{
|
|
668 |
if(lst.isEmpty())
|
|
669 |
lst = findTileLine4Update(true, true);
|
|
670 |
if(lst.isEmpty())
|
|
671 |
lst = findTileLine4Update(true, false);
|
|
672 |
if(lst.isEmpty())
|
|
673 |
lst = findTileLine4Update(true, false, false);
|
|
674 |
}
|
|
675 |
|
|
676 |
QTime ts;
|
|
677 |
ts.start();
|
|
678 |
foreach(QPoint t, lst) {
|
|
679 |
QRectF r = updateTile(t);
|
|
680 |
dirtyRects += r;
|
|
681 |
if(updatedTiles)
|
|
682 |
*updatedTiles += TileSet(t, r);
|
|
683 |
if(inPaint && ts.elapsed() > cInPaintTileUpdateTimeout)
|
|
684 |
break;
|
|
685 |
}
|
|
686 |
|
|
687 |
return dirtyRects;
|
|
688 |
}
|
|
689 |
|
|
690 |
|
|
691 |
void TiledWebView::updateTimeout()
|
|
692 |
{
|
|
693 |
if(m_tilesFrozen) return;
|
|
694 |
if(m_inUpdate) return;
|
|
695 |
|
|
696 |
int elapsed = m_userPaintTS.elapsed();
|
|
697 |
QList<QRectF> dirtyTiles;
|
|
698 |
|
|
699 |
if(m_needTilesFieldRebuild) {
|
|
700 |
doTilesFieldRebuild();
|
|
701 |
} else if(m_needScaleCommit) {
|
|
702 |
doScaleCommit();
|
|
703 |
} else if(m_needViewportTilesUpdate) {
|
|
704 |
/* just do nothing, because it will update tiles below
|
|
705 |
dirtyTiles += updateViewportTiles(); */
|
|
706 |
} else if(elapsed < cPaintIdleTimeout) {
|
|
707 |
// updateSceneRects(updateScrollAreaTilesChunk);
|
|
708 |
|
|
709 |
/* QList<QRectF> rects = updateViewportTiles();
|
|
710 |
foreach(QRectF r, rects)
|
|
711 |
update(r); */
|
|
712 |
return;
|
|
713 |
}
|
|
714 |
|
|
715 |
if(elapsed > cTileScaleUpdateTimeout && !qFuzzyCompare(m_tilesScale, scale())) {
|
|
716 |
doScaleCommit();
|
|
717 |
}
|
|
718 |
// else if(elapsed > cTileRectRecenterTimeout && !m_tilesRectCentered)
|
|
719 |
// adjustTilesToViewPort(true);
|
|
720 |
|
|
721 |
dirtyTiles += updateViewportTiles();
|
|
722 |
if(dirtyTiles.isEmpty())
|
|
723 |
dirtyTiles = updateScrollAreaTilesChunk();
|
|
724 |
|
|
725 |
if(dirtyTiles.isEmpty())
|
|
726 |
for(int i = 0; i < cIdleTileUpdateChunkSize; i++) {
|
|
727 |
// 1st try to paint not ready tiles in view
|
|
728 |
QPoint oneDirtyTile = findTile4Update(true);
|
|
729 |
// 2nd update dirty tiles in view
|
|
730 |
if(oneDirtyTile.x() < 0) oneDirtyTile = findTile4Update(true, true);
|
|
731 |
// 3rd try to paint not ready tiles everywhere else
|
|
732 |
if(oneDirtyTile.x() < 0) oneDirtyTile = findTile4Update(false);
|
|
733 |
// 4th update all other dirty tiles
|
|
734 |
if(oneDirtyTile.x() < 0) oneDirtyTile = findTile4Update(false, true);
|
|
735 |
if(oneDirtyTile.x() >= 0)
|
|
736 |
dirtyTiles += updateTile(oneDirtyTile);
|
|
737 |
else if(/*m_tilesRectCentered && */qFuzzyCompare(m_tilesScale, scale())) {
|
|
738 |
stopUpdateTimer();
|
|
739 |
break;
|
|
740 |
}
|
|
741 |
}
|
|
742 |
|
|
743 |
m_inUpdate = true;
|
|
744 |
|
|
745 |
updateSceneRects(dirtyTiles);
|
|
746 |
|
|
747 |
m_inUpdate = false;
|
|
748 |
|
|
749 |
// restart timer if some of update flags was set during recursive calls from webkit render
|
|
750 |
if(m_needTilesFieldRebuild || m_needScaleCommit || m_needViewportTilesUpdate)
|
|
751 |
startUpdateTimer();
|
|
752 |
}
|
|
753 |
|
|
754 |
void TiledWebView::updateSceneRects(const QList<QRectF>& dirtyTiles)
|
|
755 |
{
|
|
756 |
QGraphicsScene* s = scene();
|
|
757 |
QList<QGraphicsView*> gvList = s->views();
|
|
758 |
|
|
759 |
QRectF vpRect = viewPortRect();
|
|
760 |
|
|
761 |
foreach(QGraphicsView* v, gvList) {
|
|
762 |
QRegion reg;
|
|
763 |
foreach(QRectF r, dirtyTiles) {
|
|
764 |
r = r.intersected(vpRect);
|
|
765 |
update(r);
|
|
766 |
r = mapRectToScene(r);
|
|
767 |
r = v->mapFromScene(r).boundingRect();
|
|
768 |
reg += r.toRect();
|
|
769 |
}
|
|
770 |
// v->repaint(reg);
|
|
771 |
}
|
|
772 |
}
|
|
773 |
|
|
774 |
void TiledWebView::scheduleScaleUpdate()
|
|
775 |
{
|
|
776 |
if(!m_tilesField) return;
|
|
777 |
|
|
778 |
startUpdateTimer();
|
|
779 |
}
|
|
780 |
|
|
781 |
void TiledWebView::checkTilesField()
|
|
782 |
{
|
|
783 |
int usedCount1 = 0;
|
|
784 |
for(int j = 0; j < m_tilesDim.height(); j++)
|
|
785 |
for(int i = 0; i < m_tilesDim.width(); i++) {
|
|
786 |
Tile* t = tileAt(i, j);
|
|
787 |
if(t) {
|
|
788 |
Q_ASSERT(t->used);
|
|
789 |
usedCount1++;
|
|
790 |
}
|
|
791 |
}
|
|
792 |
|
|
793 |
int usedCount2 = 0;
|
|
794 |
for(int i = 0; i < m_tilesPool.count(); i++)
|
|
795 |
if(m_tilesPool[i] && m_tilesPool[i]->used)
|
|
796 |
usedCount2++;
|
|
797 |
|
|
798 |
Q_ASSERT(usedCount1 == usedCount2);
|
|
799 |
}
|
|
800 |
|
|
801 |
void TiledWebView::doTilesFieldRebuild()
|
|
802 |
{
|
|
803 |
QSize oldDim = m_tilesDim;
|
|
804 |
QSize newDim = getTileFieldDim();
|
|
805 |
|
|
806 |
if(!qFuzzyCompare(m_tilesScale, scale())) {
|
|
807 |
resetTiles(QRect(QPoint(0,0), m_tilesDim), true);
|
|
808 |
m_tilesScale = scale();
|
|
809 |
|
|
810 |
QRectF newRect = adjustedTileRect(newDim);
|
|
811 |
|
|
812 |
Tile** newField = new Tile*[newDim.width() * newDim.height()];
|
|
813 |
memset(newField, 0, sizeof(Tile*) * newDim.width() * newDim.height());
|
|
814 |
delete[] m_tilesField;
|
|
815 |
m_tilesField = newField;
|
|
816 |
m_tilesDim = newDim;
|
|
817 |
m_tilesRect = newRect;
|
|
818 |
|
|
819 |
m_needViewportTilesUpdate = true;
|
|
820 |
|
|
821 |
} else {
|
|
822 |
Tile** oldField = m_tilesField;
|
|
823 |
QRectF newRect = adjustedTileRect(newDim);
|
|
824 |
|
|
825 |
QRectF trNew = mapToTileCoords(newRect);
|
|
826 |
QRectF trOld = mapToTileCoords(m_tilesRect);
|
|
827 |
|
|
828 |
if(trNew != trOld) {
|
|
829 |
|
|
830 |
Tile** newField = new Tile*[newDim.width() * newDim.height()];
|
|
831 |
memset(newField, 0, sizeof(Tile*) * newDim.width() * newDim.height());
|
|
832 |
QRectF trCommon = trNew.intersect(trOld);
|
|
833 |
|
|
834 |
if(!trCommon.isEmpty()) {
|
|
835 |
QSize copySize = (trCommon.size() / cTileSize).toSize();
|
|
836 |
QPoint oldOffs = ((trCommon.topLeft() - trOld.topLeft()) / cTileSize).toPoint();
|
|
837 |
QPoint newOffs = ((trCommon.topLeft() - trNew.topLeft()) / cTileSize).toPoint();
|
|
838 |
if(trNew.size().width() - newOffs.x() < copySize.width())
|
|
839 |
copySize.setWidth(trNew.size().width() - newOffs.x());
|
|
840 |
if(trNew.size().height() - newOffs.y() < copySize.height())
|
|
841 |
copySize.setHeight(trNew.size().height() - newOffs.y());
|
|
842 |
if(trOld.size().width() - oldOffs.x() < copySize.width())
|
|
843 |
copySize.setWidth(trOld.size().width() - oldOffs.x());
|
|
844 |
if(trOld.size().height() - oldOffs.y() < copySize.height())
|
|
845 |
copySize.setHeight(trOld.size().height() - oldOffs.y());
|
|
846 |
|
|
847 |
for(int j = 0; j < copySize.height(); j++)
|
|
848 |
for(int i = 0; i < copySize.width(); i++) {
|
|
849 |
QPoint cPoint(i, j);
|
|
850 |
QPoint oldPos = cPoint + oldOffs;
|
|
851 |
Tile *tile = tileAt(oldPos);
|
|
852 |
setTileAt(oldPos, 0);
|
|
853 |
QPoint newPos = cPoint + newOffs;
|
|
854 |
Q_ASSERT(newPos.x() >= 0 && newPos.y() >=0 &&
|
|
855 |
newPos.x() < newDim.width() && newPos.y() < newDim.height());
|
|
856 |
*(newField + newPos.y() * newDim.width() + newPos.x()) = tile;
|
|
857 |
}
|
|
858 |
}
|
|
859 |
|
|
860 |
// release remaining tiles in old field
|
|
861 |
resetTiles(QRect(QPoint(0,0), m_tilesDim), true);
|
|
862 |
|
|
863 |
delete[] m_tilesField;
|
|
864 |
m_tilesField = newField;
|
|
865 |
m_tilesDim = newDim;
|
|
866 |
m_tilesRect = newRect;
|
|
867 |
|
|
868 |
int newTileCount = m_tilesDim.height() * m_tilesDim.width();
|
|
869 |
while(m_tilesPool.count() > newTileCount) {
|
|
870 |
bool deleted = false;
|
|
871 |
for(int i = m_tilesPool.count() - 1; i >= 0; i--) {
|
|
872 |
Tile* tile = m_tilesPool[i];
|
|
873 |
if(!tile->used) {
|
|
874 |
deleted = true;
|
|
875 |
if(tile) delete tile;
|
|
876 |
m_tilesPool.remove(i);
|
|
877 |
break;
|
|
878 |
}
|
|
879 |
}
|
|
880 |
Q_ASSERT(deleted);
|
|
881 |
}
|
|
882 |
|
|
883 |
m_needViewportTilesUpdate = true;
|
|
884 |
}
|
|
885 |
}
|
|
886 |
|
|
887 |
m_needTilesFieldRebuild = false;
|
|
888 |
}
|
|
889 |
|
|
890 |
void TiledWebView::viewportUpdated()
|
|
891 |
{
|
|
892 |
if(!m_tilesField) {
|
|
893 |
createTileField();
|
|
894 |
commitZoom();
|
|
895 |
}
|
|
896 |
else {
|
|
897 |
m_needTilesFieldRebuild = true;
|
|
898 |
startUpdateTimer();
|
|
899 |
}
|
|
900 |
}
|
|
901 |
|
|
902 |
// #define DRAW_TILE_BOUNDS
|
|
903 |
void TiledWebView::paintTile(QPainter* painter, const QPoint& t, const QRectF& clipRect, QRegion& dirtyRegion)
|
|
904 |
{
|
|
905 |
QRectF tRectOrig = tileRect(t);
|
|
906 |
qreal adjust = 1; // + m_tilesScale;
|
|
907 |
QRectF tRect = tRectOrig.adjusted(-adjust, -adjust, adjust, adjust);
|
|
908 |
QRectF drawRect = clipRect.intersected(tRect);
|
|
909 |
//painter->drawPixmap(tRectOrig,tileAt(t)->img, tRectOrig.translated(-tRectOrig.topLeft()));
|
|
910 |
painter->drawPixmap(tRectOrig.topLeft(),tileAt(t)->img);
|
|
911 |
#ifdef DRAW_TILE_BOUNDS
|
|
912 |
painter->setPen(Qt::red);
|
|
913 |
painter->drawRect(tileRect(t));
|
|
914 |
#endif // DRAW_TILE_BOUNDS
|
|
915 |
dirtyRegion = dirtyRegion.subtract(QRegion(mapFromTileCoords(drawRect).toRect()));
|
|
916 |
}
|
|
917 |
|
|
918 |
void TiledWebView::paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
|
|
919 |
{
|
|
920 |
|
|
921 |
if(!m_tilesField) {
|
|
922 |
QGraphicsWebView::paint(painter, options, widget );
|
|
923 |
return;
|
|
924 |
}
|
|
925 |
|
|
926 |
painter->save();
|
|
927 |
QRectF clipRect = viewPortRect().adjusted(-1, -1, 1, 1);
|
|
928 |
if(options && !options->exposedRect.isEmpty())
|
|
929 |
clipRect &= options->exposedRect;
|
|
930 |
|
|
931 |
QList<QRectF> updatedTileRects;
|
|
932 |
QList<TileSet> updatedTiles;
|
|
933 |
if(!m_inUpdate && !m_tilesFrozen) {
|
|
934 |
QList<QRectF> lst;
|
|
935 |
if(m_userPaintTS.elapsed() > cPaintIdleTimeout || m_needViewportTilesUpdate) {
|
|
936 |
lst = updateViewportTiles(&updatedTiles);
|
|
937 |
m_needViewportTilesUpdate = false;
|
|
938 |
} else
|
|
939 |
lst = updateScrollAreaTilesChunk(&updatedTiles, true);
|
|
940 |
QRectF vpRect = viewPortRect().adjusted(-1, -1, 1, 1);
|
|
941 |
foreach(QRectF r, lst) {
|
|
942 |
r = r.intersected(vpRect);
|
|
943 |
if(!r.isEmpty()) {
|
|
944 |
if(clipRect.contains(r)) {
|
|
945 |
// do nothing, it will be updated in any case
|
|
946 |
} else if(r.contains(clipRect)) {
|
|
947 |
clipRect = r;
|
|
948 |
} else if(clipRect.intersects(r)) {
|
|
949 |
clipRect = clipRect.unite(r);
|
|
950 |
} else {
|
|
951 |
updatedTileRects += r;
|
|
952 |
}
|
|
953 |
}
|
|
954 |
}
|
|
955 |
}
|
|
956 |
|
|
957 |
painter->setBackgroundMode(Qt::OpaqueMode);
|
|
958 |
|
|
959 |
painter->setClipRect(clipRect, Qt::IntersectClip);
|
|
960 |
|
|
961 |
QRectF tileClipRect = mapToTileCoords(clipRect);
|
|
962 |
QRegion dirtyRgn(clipRect.toRect());
|
|
963 |
QPoint topLeftTile = tileAtPoint(clipRect.topLeft());
|
|
964 |
QPoint rightBottomTile = tileAtPoint(clipRect.bottomRight());
|
|
965 |
|
|
966 |
boundPoint(QPoint(0,0),topLeftTile,topPoint(m_tilesDim));
|
|
967 |
boundPoint(QPoint(0,0),rightBottomTile,topPoint(m_tilesDim));
|
|
968 |
|
|
969 |
qreal sc = scale();
|
|
970 |
QPointF p = pos() / sc;
|
|
971 |
|
|
972 |
QRectF scr(clipRect.topLeft() + p, clipRect.size() * sc);
|
|
973 |
|
|
974 |
QRegion notReadyClip(scr.toRect()); //.adjusted(-2, -2, 2, 2).toRect());
|
|
975 |
for(int j = topLeftTile.y(); j <= rightBottomTile.y(); j++)
|
|
976 |
for(int i = topLeftTile.x(); i <= rightBottomTile.x(); i++) {
|
|
977 |
QPoint t(i,j);
|
|
978 |
if(tileAt(t) && tileAt(t)->ready) {
|
|
979 |
QRectF r = mapFromTileCoords(tileRect(t));
|
|
980 |
r = QRectF(r.topLeft() * sc, r.size() * sc);
|
|
981 |
r.translate(pos());
|
|
982 |
notReadyClip = notReadyClip.subtract(r.toRect());
|
|
983 |
// painter->setPen(Qt::red);
|
|
984 |
// painter->drawRect(r);
|
|
985 |
}
|
|
986 |
}
|
|
987 |
|
|
988 |
// painter->setPen(Qt::red);
|
|
989 |
// painter->drawRect(scr.adjusted(10,10,-10,-10));
|
|
990 |
|
|
991 |
QVector<QRect> rList = notReadyClip.rects();
|
|
992 |
if(!rList.isEmpty()) {
|
|
993 |
painter->save();
|
|
994 |
painter->translate(-p);
|
|
995 |
painter->scale(1/sc, 1/sc);
|
|
996 |
foreach(QRect r, rList) {
|
|
997 |
painter->fillRect(r, QBrush(*getUnprepPixmap()));
|
|
998 |
// painter->setPen(Qt::red);
|
|
999 |
// painter->drawRect(r.adjusted(10, 10, -10, -10));
|
|
1000 |
}
|
|
1001 |
painter->restore();
|
|
1002 |
}
|
|
1003 |
|
|
1004 |
painter->scale(1 / m_tilesScale, 1 / m_tilesScale);
|
|
1005 |
|
|
1006 |
for(int j = topLeftTile.y(); j <= rightBottomTile.y(); j++)
|
|
1007 |
for(int i = topLeftTile.x(); i <= rightBottomTile.x(); i++) {
|
|
1008 |
QPoint t(i,j);
|
|
1009 |
if(tileAt(t) && tileAt(t)->ready)
|
|
1010 |
paintTile(painter, t, tileClipRect, dirtyRgn);
|
|
1011 |
}
|
|
1012 |
QRect clippedRectTiles(topLeftTile,rightBottomTile);
|
|
1013 |
foreach(TileSet ts, updatedTiles)
|
|
1014 |
if(!clippedRectTiles.contains(ts.t))
|
|
1015 |
paintTile(painter, ts.t, ts.r, dirtyRgn);
|
|
1016 |
|
|
1017 |
// if(!m_inUpdate)
|
|
1018 |
// m_userPaintTS.start();
|
|
1019 |
|
|
1020 |
if(!m_tilesFrozen && !m_tilesRect.contains(viewPortRect()) && qFuzzyCompare(scale(),m_tilesScale)) {
|
|
1021 |
adjustTilesToViewPort();
|
|
1022 |
startUpdateTimer();
|
|
1023 |
}
|
|
1024 |
/* painter->setPen(Qt::red);
|
|
1025 |
painter->drawLine(0, 0, 100, 100);
|
|
1026 |
*/
|
|
1027 |
painter->restore();
|
|
1028 |
}
|
|
1029 |
|
|
1030 |
void TiledWebView::setTiledBackingStoreFrozen(bool frozen)
|
|
1031 |
{
|
|
1032 |
m_tilesFrozen = frozen;
|
|
1033 |
if(frozen) {
|
|
1034 |
if(m_updateTimer.isActive())
|
|
1035 |
stopUpdateTimer();
|
|
1036 |
} else {
|
|
1037 |
if(!qFuzzyCompare(scale(),m_tilesScale))
|
|
1038 |
commitZoom();
|
|
1039 |
else {
|
|
1040 |
// m_needViewportTilesUpdate = true;
|
|
1041 |
m_tilesRectCentered = false;
|
|
1042 |
}
|
|
1043 |
|
|
1044 |
startUpdateTimer();
|
|
1045 |
}
|
|
1046 |
}
|
|
1047 |
|
|
1048 |
void TiledWebView::startUpdateTimer()
|
|
1049 |
{
|
|
1050 |
if(!m_updateTimer.isActive() && !m_tilesFrozen) {
|
|
1051 |
m_updateTimer.start(cTileUpdateTimerTick);
|
|
1052 |
}
|
|
1053 |
}
|
|
1054 |
|
|
1055 |
void TiledWebView::stopUpdateTimer()
|
|
1056 |
{
|
|
1057 |
m_updateTimer.stop();
|
|
1058 |
}
|
|
1059 |
|
|
1060 |
void TiledWebView::userActivity()
|
|
1061 |
{
|
|
1062 |
m_userPaintTS.start();
|
|
1063 |
}
|
|
1064 |
|
|
1065 |
void TiledWebView::viewScrolled(QPoint& scrollPos, QPoint& delta)
|
|
1066 |
{
|
|
1067 |
m_lastScrollDelta = delta;
|
|
1068 |
|
|
1069 |
userActivity();
|
|
1070 |
if(!m_tilesField) return;
|
|
1071 |
|
|
1072 |
QRectF ret(m_tilesRect);
|
|
1073 |
if(ret.isEmpty())
|
|
1074 |
ret = QRectF(QPoint(0,0),mapFromTileCoords(m_tilesDim * cTileSize));
|
|
1075 |
// no repositioning and scaling and tile dropping during scaling
|
|
1076 |
if(!qFuzzyCompare(m_tilesScale,scale()))
|
|
1077 |
return;
|
|
1078 |
|
|
1079 |
QRectF vpRect = viewPortRect();
|
|
1080 |
qreal tileSize = cTileSize / m_tilesScale;
|
|
1081 |
vpRect.adjust(-tileSize, -tileSize, tileSize, tileSize);
|
|
1082 |
if(vpRect.bottom() > ret.bottom() && delta.y() > 0)
|
|
1083 |
ret.moveTop(vpRect.top() - tileSize);
|
|
1084 |
else if(vpRect.top() < ret.top() && delta.y() < 0)
|
|
1085 |
ret.moveBottom(vpRect.bottom() + tileSize);
|
|
1086 |
|
|
1087 |
if(vpRect.right() > ret.right() && delta.x() > 0)
|
|
1088 |
ret.moveLeft(vpRect.left() - tileSize);
|
|
1089 |
else if(vpRect.left() < ret.left() & delta.x() < 0)
|
|
1090 |
ret.moveRight(vpRect.right() + tileSize);
|
|
1091 |
|
|
1092 |
ret = validateTileRect(ret, m_tilesDim);
|
|
1093 |
|
|
1094 |
moveTilesRect(ret);
|
|
1095 |
}
|
|
1096 |
|
|
1097 |
#ifdef USE_ASSISTANT_ITEM
|
|
1098 |
|
|
1099 |
void TiledWebView::resizeEvent(QGraphicsSceneResizeEvent *event)
|
|
1100 |
{
|
|
1101 |
m_assistant->setGeometry(QRectF(QPoint(0,0), event->newSize()));
|
|
1102 |
}
|
|
1103 |
|
|
1104 |
void TiledWebViewAssistant::paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
|
|
1105 |
{
|
|
1106 |
m_master->paint(painter, options, widget);
|
|
1107 |
}
|
|
1108 |
#endif
|