📄 loader.cpp
字号:
{
if(eof && pos == buffer.size())
return -1;
return buffer.size() - pos;
}
void ImageSource::sendTo(QDataSink* sink, int n)
{
sink->receive((const uchar*)&buffer.at(pos), n);
pos += n;
// buffer is no longer needed
if(eof && pos == buffer.size() && !rewable)
{
buffer.resize(0);
pos = 0;
}
}
void ImageSource::setEOF( bool state )
{
eof = state;
}
// ImageSource's is rewindable.
bool ImageSource::rewindable() const
{
return rewable;
}
// Enables rewinding. No special action is taken.
void ImageSource::enableRewind(bool on)
{
rew = on;
}
// Calls reset() on the QIODevice.
void ImageSource::rewind()
{
pos = 0;
if (!rew) {
QDataSource::rewind();
} else
ready();
}
void ImageSource::cleanBuffer()
{
// if we need to be able to rewind, buffer is needed
if(rew)
return;
rewable = false;
// buffer is no longer needed
if(eof && pos == buffer.size())
{
buffer.resize(0);
pos = 0;
}
}
static QString buildAcceptHeader()
{
QString result = KImageIO::mimeTypes( KImageIO::Reading ).join(", ");
if (result.right(2) == ", ")
result = result.left(result.length()-2);
return result;
}
#endif // APPLE_CHANGES
static bool crossDomain(const QString &a, const QString &b)
{
if (a == b) return false;
QStringList l1 = QStringList::split('.', a);
QStringList l2 = QStringList::split('.', b);
while(l1.count() > l2.count())
l1.pop_front();
while(l2.count() > l1.count())
l2.pop_front();
while(l2.count() >= 2)
{
if (l1 == l2)
return false;
l1.pop_front();
l2.pop_front();
}
return true;
}
// -------------------------------------------------------------------------------------
#if APPLE_CHANGES
void CachedImageCallback::notifyUpdate()
{
if (cachedImage) {
cachedImage->do_notify (cachedImage->pixmap(), cachedImage->pixmap().rect());
QSize s = cachedImage->pixmap_size();
cachedImage->setSize(s.width() * s.height() * 2);
// After receiving the image header we are guaranteed to know
// the image size. Although all of the data may not have arrived or
// been decoded we can consider the image loaded for purposed of
// layout and dispatching the image's onload handler. Removing the request from
// the list of background decoding requests will ensure that Loader::numRequests()
// does not count this background request. Further numRequests() can
// be correctly used by the part to determine if loading is sufficiently
// complete to dispatch the page's onload handler.
Request *r = cachedImage->m_request;
if( r ) {
DocLoader *dl = r->m_docLoader;
khtml::Cache::loader()->removeBackgroundDecodingRequest(r);
// Poke the part to get it to do a checkCompleted(). Only do this for
// the first update to minimize work. Note that we are guaranteed to have
// read the header when we received this first update, which is triggered
// by the first kCGImageStatusIncomplete status from CG. kCGImageStatusIncomplete
// really means that the CG decoder is waiting for more data, but has already
// read the header.
if (!headerReceived) {
emit khtml::Cache::loader()->requestDone( dl, cachedImage );
headerReceived = true;
}
}
}
}
void CachedImageCallback::notifyFinished()
{
if (cachedImage) {
cachedImage->do_notify (cachedImage->pixmap(), cachedImage->pixmap().rect());
cachedImage->m_loading = false;
cachedImage->checkNotify();
QSize s = cachedImage->pixmap_size();
cachedImage->setSize(s.width() * s.height() * 2);
Request *r = cachedImage->m_request;
if( r ) {
DocLoader *dl = r->m_docLoader;
khtml::Cache::loader()->removeBackgroundDecodingRequest(r);
// Poke the part to get it to do a checkCompleted().
emit khtml::Cache::loader()->requestDone( dl, cachedImage );
delete r;
}
}
}
void CachedImageCallback::notifyDecodingError()
{
if (cachedImage) {
handleError();
}
}
void CachedImageCallback::handleError()
{
if (cachedImage) {
cachedImage->errorOccured = true;
QPixmap ep = cachedImage->pixmap();
cachedImage->do_notify (ep, ep.rect());
Cache::removeCacheEntry (cachedImage);
clear();
}
}
void CachedImageCallback::clear()
{
if (cachedImage && cachedImage->m_request) {
Request *r = cachedImage->m_request;
DocLoader *dl = r->m_docLoader;
khtml::Cache::loader()->removeBackgroundDecodingRequest(r);
// Poke the part to get it to do a checkCompleted().
emit khtml::Cache::loader()->requestFailed( dl, cachedImage );
delete r;
}
cachedImage = 0;
}
#endif
CachedImage::CachedImage(DocLoader* dl, const DOMString &url, KIO::CacheControl _cachePolicy, time_t _expireDate)
: QObject(), CachedObject(url, Image, _cachePolicy, _expireDate)
#if APPLE_CHANGES
, m_dataSize(0)
#endif
{
#if !APPLE_CHANGES
static const QString &acceptHeader = KGlobal::staticQString( buildAcceptHeader() );
#endif
m = 0;
p = 0;
pixPart = 0;
bg = 0;
#if !APPLE_CHANGES
bgColor = qRgba( 0, 0, 0, 0xFF );
typeChecked = false;
#endif
isFullyTransparent = false;
errorOccured = false;
monochrome = false;
formatType = 0;
m_status = Unknown;
imgSource = 0;
m_loading = true;
#if !APPLE_CHANGES
setAccept( acceptHeader );
#endif
#if NOKIA_CHANGES
setAccept( QString::fromLatin1("*/*") );
#endif
m_showAnimations = dl->showAnimations();
#if APPLE_CHANGES
#if BUILDING_ON_PANTHER
m_decoderCallback = 0;
#else
if (QPixmap::shouldUseThreadedDecoding())
m_decoderCallback = new CachedImageCallback(this);
else
m_decoderCallback = 0;
#endif
#endif
}
CachedImage::~CachedImage()
{
clear();
}
void CachedImage::ref( CachedObjectClient *c )
{
#ifdef CACHE_DEBUG
kdDebug( 6060 ) << this << " CachedImage::ref(" << c << ") " << endl;
#endif
CachedObject::ref(c);
if( m ) {
m->unpause();
if( m->finished() || m_clients.count() == 1 )
m->restart();
}
// for mouseovers, dynamic changes
if (!valid_rect().isNull())
c->setPixmap( pixmap(), valid_rect(), this);
if(!m_loading) c->notifyFinished(this);
}
void CachedImage::deref( CachedObjectClient *c )
{
#ifdef CACHE_DEBUG
kdDebug( 6060 ) << this << " CachedImage::deref(" << c << ") " << endl;
#endif
Cache::flush();
CachedObject::deref(c);
if(m && m_clients.isEmpty() && m->running())
m->pause();
if ( canDelete() && m_free )
delete this;
}
#define BGMINWIDTH 32
#define BGMINHEIGHT 32
const QPixmap &CachedImage::tiled_pixmap(const QColor& newc)
{
#if APPLE_CHANGES
return pixmap();
#else
static QRgb bgTransparant = qRgba( 0, 0, 0, 0xFF );
if ( (bgColor != bgTransparant) && (bgColor != newc.rgb()) ) {
delete bg; bg = 0;
}
if (bg)
return *bg;
const QPixmap &r = pixmap();
if (r.isNull()) return r;
// no error indication for background images
if(errorOccured) return *Cache::nullPixmap;
bool isvalid = newc.isValid();
QSize s(pixmap_size());
int w = r.width();
int h = r.height();
if ( w*h < 8192 )
{
if ( r.width() < BGMINWIDTH )
w = ((BGMINWIDTH / s.width())+1) * s.width();
if ( r.height() < BGMINHEIGHT )
h = ((BGMINHEIGHT / s.height())+1) * s.height();
}
if ( (w != r.width()) || (h != r.height()) || (isvalid && r.mask()))
{
QPixmap pix = r;
if ( w != r.width() || (isvalid && pix.mask()))
{
bg = new QPixmap(w, r.height());
QPainter p(bg);
if(isvalid) p.fillRect(0, 0, w, r.height(), newc);
p.drawTiledPixmap(0, 0, w, r.height(), pix);
if(!isvalid && pix.mask())
{
// unfortunately our anti-transparency trick doesn't work here
// we need to create a mask.
QBitmap newmask(w, r.height());
QPainter pm(&newmask);
pm.drawTiledPixmap(0, 0, w, r.height(), *pix.mask());
bg->setMask(newmask);
bgColor = bgTransparant;
}
else
bgColor= newc.rgb();
pix = *bg;
}
if ( h != r.height() )
{
delete bg;
bg = new QPixmap(w, h);
QPainter p(bg);
if(isvalid) p.fillRect(0, 0, w, h, newc);
p.drawTiledPixmap(0, 0, w, h, pix);
if(!isvalid && pix.mask())
{
// unfortunately our anti-transparency trick doesn't work here
// we need to create a mask.
QBitmap newmask(w, h);
QPainter pm(&newmask);
pm.drawTiledPixmap(0, 0, w, h, *pix.mask());
bg->setMask(newmask);
bgColor = bgTransparant;
}
else
bgColor= newc.rgb();
}
return *bg;
}
return r;
#endif
}
const QPixmap &CachedImage::pixmap( ) const
{
if(errorOccured)
return *Cache::brokenPixmap;
#if NOKIA_CHANGES
if (isErrorImage())
return *Cache::brokenPixmap;
#endif
#if APPLE_CHANGES
if (p)
return *p;
#else
if(m)
{
if(m->framePixmap().size() != m->getValidRect().size() && m->getValidRect().size().isValid())
{
// pixmap is not yet completely loaded, so we
// return a clipped version. asserting here
// that the valid rect is always from 0/0 to fullwidth/ someheight
if(!pixPart) pixPart = new QPixmap(m->getValidRect().size());
(*pixPart) = m->framePixmap();
pixPart->resize(m->getValidRect().size());
return *pixPart;
}
else
return m->framePixmap();
}
else if(p)
return *p;
#endif // APPLE_CHANGES
return *Cache::nullPixmap;
}
QSize CachedImage::pixmap_size() const
{
return (m ? m->framePixmap().size() : ( p ? p->size() : QSize()));
}
QRect CachedImage::valid_rect() const
{
return m ? m->getValidRect() : ( p ? p->rect() : QRect());
}
void CachedImage::do_notify(const QPixmap& p, const QRect& r)
{
CachedObjectClientWalker w(m_clients);
while (CachedObjectClient *c = w.next())
c->setPixmap(p, r, this);
}
#if !APPLE_CHANGES
void CachedImage::movieUpdated( const QRect& r )
{
#ifdef CACHE_DEBUG
qDebug("movie updated %d/%d/%d/%d, pixmap size %d/%d", r.x(), r.y(), r.right(), r.bottom(),
m->framePixmap().size().width(), m->framePixmap().size().height());
#endif
do_notify(m->framePixmap(), r);
}
void CachedImage::movieStatus(int status)
{
#ifdef CACHE_DEBUG
qDebug("movieStatus(%d)", status);
#endif
// ### the html image objects are supposed to send the load event after every frame (according to
// netscape). We have a problem though where an image is present, and js code creates a new Image object,
// which uses the same CachedImage, the one in the document is not supposed to be notified
// just another Qt 2.2.0 bug. we cannot call
// QMovie::frameImage if we're after QMovie::EndOfMovie
if(status == QMovie::EndOfFrame)
{
const QImage& im = m->frameImage();
monochrome = ( ( im.depth() <= 8 ) && ( im.numColors() - int( im.hasAlphaBuffer() ) <= 2 ) );
for (int i = 0; monochrome && i < im.numColors(); ++i)
if (im.colorTable()[i] != qRgb(0xff, 0xff, 0xff) &&
im.colorTable()[i] != qRgb(0x00, 0x00, 0x00))
monochrome = false;
if((im.width() < 5 || im.height() < 5) && im.hasAlphaBuffer()) // only evaluate for small images
{
QImage am = im.createAlphaMask();
if(am.depth() == 1)
{
bool solid = false;
for(int y = 0; y < am.height(); y++)
for(int x = 0; x < am.width(); x++)
if(am.pixelIndex(x, y)) {
solid = true;
break;
}
isFullyTransparent = (!solid);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -