GP<DjVuImage> DjVuSource::GetPage(int nPage, Observer* observer) { ASSERT(nPage >= 0 && nPage < m_nPageCount); PageData& data = m_pages[nPage]; m_lock.Lock(); GP<DjVuImage> pImage = data.pImage; if (pImage != NULL) { m_lock.Unlock(); return pImage; } if (data.hDecodingThread != NULL) { // Another thread is already decoding this page. Put // ourselves in a list of waiting threads PageRequest request; m_eventLock.Lock(); if (m_eventCache.empty()) { request.hEvent = ::CreateEvent(NULL, false, false, NULL); } else { request.hEvent = m_eventCache.top(); ::ResetEvent(request.hEvent); m_eventCache.pop(); } m_eventLock.Unlock(); // Temporarily increase priority of the decoding thread if needed HANDLE hOurThread = ::GetCurrentThread(); int nOurPriority = ::GetThreadPriority(hOurThread); if (::GetThreadPriority(data.hDecodingThread) < nOurPriority) ::SetThreadPriority(data.hDecodingThread, nOurPriority); data.requests.push_back(&request); if (observer != NULL) data.AddObserver(observer); m_lock.Unlock(); ::WaitForSingleObject(request.hEvent, INFINITE); pImage = request.pImage; m_eventLock.Lock(); m_eventCache.push(request.hEvent); m_eventLock.Unlock(); // Page will be put in cache by the thread which decoded it return pImage; } data.hDecodingThread = ::GetCurrentThread(); data.nOrigThreadPriority = ::GetThreadPriority(data.hDecodingThread); m_lock.Unlock(); try { GP<DjVuFile> file = m_pDjVuDoc->get_djvu_file(nPage); if (file) { pImage = DjVuImage::create(file); file->resume_decode(); if (pImage && THREADMODEL != NOTHREADS) pImage->wait_for_complete_decode(); } } catch (GException&) { } catch (...) { if (pApplication != NULL) pApplication->ReportFatalError(); } m_lock.Lock(); if (pImage != NULL) { pImage->set_rotate(0); if (observer != NULL || data.HasObservers()) { data.pImage = pImage; if (observer != NULL) data.AddObserver(observer); } data.info.Update(pImage); if (data.info.bHasText) m_bHasText = true; } // Notify all waiting threads that image is ready for (size_t i = 0; i < data.requests.size(); ++i) { data.requests[i]->pImage = pImage; ::SetEvent(data.requests[i]->hEvent); } ASSERT(data.hDecodingThread == ::GetCurrentThread()); ::SetThreadPriority(data.hDecodingThread, data.nOrigThreadPriority); data.hDecodingThread = NULL; data.requests.clear(); m_lock.Unlock(); return pImage; }