Changeset 130

Show
Ignore:
Timestamp:
04/29/06 06:04:59 (2 years ago)
Author:
jordi
Message:

I added a new IJob child class called JobRender? which just renders pages. This class also needs a mutex because when it's rendering it could be that the document disapears (actually I think this happens only when testing), so I added a boolean variable to know when stop processing jobs, and also a way to "clear" the async queue.

Location:
trunk
Files:
2 added
8 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/IDocument.cxx

    r129 r130  
    2222using namespace ePDFView; 
    2323 
    24 G_LOCK_DEFINE_STATIC (rendering); 
    25 #define WAIT_REQUEST(req) while (!req->done) { } 
    26  
    2724// Constants. 
    2825static const gdouble ZOOM_IN_FACTOR = 1.2; 
     
    3229static const guint CACHE_SIZE = 3; 
    3330 
    34 typedef struct 
    35 { 
    36     guint32 age; 
    37     gint pageNum; 
    38     IDocument *document; 
    39     DocumentPage *page; 
    40     volatile gboolean done; 
    41 } PageRequest; 
    42  
    4331/// This is the error domain that will be used to report Document's errors. 
    4432GQuark IDocument::errorQuark = 0; 
     33 
     34G_LOCK_EXTERN (JobRender); 
    4535 
    4636/// 
     
    128118 
    129119/// 
    130 /// @brief Renders the requested pages. 
    131 /// 
    132 /// This is a working thread that waits until a request to render 
    133 /// a page is make. Then it renders the requested page and waits 
    134 /// for another. 
    135 /// The IDocument class is responsable to make the requests. 
    136 /// 
    137 gpointer 
    138 IDocument::renderPageWorker (gpointer data) 
    139 { 
    140     GAsyncQueue *renderQueue = (GAsyncQueue *)data; 
    141     gboolean exit = FALSE; 
    142     do 
    143     { 
    144         PageRequest *request = (PageRequest *)g_async_queue_pop (renderQueue); 
    145         G_LOCK (rendering); 
    146         if ( -1 == request->pageNum ) 
    147         { 
    148             delete request; 
    149             exit = TRUE; 
    150         } 
    151         else 
    152         { 
    153             if ( 0 < request->pageNum ) 
    154             { 
    155                 request->page = new DocumentPage (); 
    156           //          request->document->renderPage (request->pageNum); 
    157             } 
    158             request->done = TRUE; 
    159         } 
    160         G_UNLOCK (rendering); 
    161     } 
    162     while (!exit); 
    163  
    164     g_async_queue_unref (renderQueue); 
    165     renderQueue = NULL; 
    166      
    167     return NULL; 
    168 } 
    169  
    170 /// 
    171120/// @brief Constructs a new IDocument object. 
    172121/// 
     
    195144    m_Subject = NULL; 
    196145    m_Title = NULL; 
    197  
    198     if ( !g_thread_supported () ) 
    199     { 
    200         g_thread_init (NULL); 
    201     } 
    202     m_RenderQueue = g_async_queue_new (); 
    203     g_async_queue_ref (m_RenderQueue); 
    204 //    g_thread_create (IDocument::renderPageWorker, (gpointer)m_RenderQueue,  
    205 //                     FALSE, NULL); 
    206146} 
    207147 
     
    211151IDocument::~IDocument () 
    212152{ 
    213     // Create a page request with an invalid page number to let know the 
    214     // thread that we are done. 
    215     PageRequest *request = new PageRequest; 
    216     memset (request, 0, sizeof (PageRequest)); 
    217     request->pageNum = -1; 
    218     g_async_queue_unref (m_RenderQueue); 
    219     g_async_queue_push (m_RenderQueue, (gpointer)request); 
    220  
    221153    g_list_free (m_Observers); 
    222154    delete m_Outline; 
     
    254186IDocument::notifyLoad () 
    255187{ 
     188    // Add the two first pages to the cache. 
     189    addPageToCache (1); 
     190    addPageToCache (2); 
     191 
    256192    for ( GList *item = g_list_first (m_Observers) ; NULL != item ; 
    257193          item = g_list_next (item) ) 
     
    293229        IDocumentObserver *observer = (IDocumentObserver *)item->data; 
    294230        observer->notifyPageChanged (pageNum); 
     231    } 
     232} 
     233#include <stdio.h> 
     234void 
     235IDocument::notifyPageRendered (gint pageNumber, DocumentPage *pageImage) 
     236{ 
     237    PageCache *cachedPage = getCachedPage (pageNumber); 
     238    if ( NULL != cachedPage ) 
     239    { 
     240        delete cachedPage->pageImage; 
     241        cachedPage->pageImage = pageImage; 
    295242    } 
    296243} 
     
    331278    job->setFileName (fileName); 
    332279    job->setPassword (password); 
    333  
    334280    IJob::queue (job); 
    335281} 
     
    781727IDocument::getCurrentPage () 
    782728{ 
    783     PageRequest *request = NULL; 
    784     for ( GList *cache = g_list_first (m_PageCache) ; 
    785           NULL != cache && NULL == request ; 
    786           cache = g_list_next (cache) ) 
    787     { 
    788         PageRequest *tmpRequest = (PageRequest *)cache->data; 
    789         if ( m_CurrentPage == tmpRequest->pageNum ) 
    790         { 
    791             request = tmpRequest; 
    792         } 
    793     } 
    794  
    795     if ( NULL == request ) 
     729    volatile PageCache *cachedPage = getCachedPage (m_CurrentPage); 
     730    if ( NULL == cachedPage ) 
    796731    { 
    797732        return NULL; 
    798733    } 
    799     WAIT_REQUEST (request); 
    800     return request->page; 
     734 
     735    while ( NULL == cachedPage->pageImage ) 
     736    { 
     737        ; 
     738    } 
     739 
     740    return cachedPage->pageImage; 
    801741} 
    802742 
     
    894834        m_CurrentPage = pageNum; 
    895835         
    896         scheduleToRender (m_CurrentPage); 
     836        addPageToCache (m_CurrentPage); 
    897837        if ( 1 < m_CurrentPage ) 
    898838        { 
    899             scheduleToRender (m_CurrentPage - 1); 
     839            addPageToCache (m_CurrentPage - 1); 
    900840        } 
    901841        if ( m_CurrentPage < getNumPages () ) 
    902842        { 
    903             scheduleToRender (m_CurrentPage + 1); 
     843            addPageToCache (m_CurrentPage + 1); 
    904844        } 
    905845 
     
    943883    if ( rotation != m_Rotation ) 
    944884    { 
     885        G_LOCK (JobRender); 
    945886        m_Rotation = (rotation % 360); 
    946887        refreshCache (); 
    947888        notifyPageRotated (); 
     889        G_UNLOCK (JobRender); 
    948890    } 
    949891} 
     
    1017959IDocument::setZoom (gdouble zoom) 
    1018960{ 
    1019     if ( ABS (zoom - m_Scale) > 0.00001 ) 
    1020     { 
     961    if ( ABS (zoom - m_Scale) > 0.00001 )     
     962    { 
     963        G_LOCK (JobRender); 
    1021964        m_Scale = zoom; 
    1022965        refreshCache (); 
    1023966        notifyPageZoomed (); 
     967        G_UNLOCK (JobRender); 
    1024968    } 
    1025969} 
     
    11011045 
    11021046/// 
    1103 /// @brief Adds a new page to be rendered. 
     1047/// @brief Adds a new page to the cache and starts to render it. 
    11041048/// 
    11051049/// This function checks if a page is already on the cache. If it is, then 
    11061050/// only updates the age and returns. Otherwise adds the page to the cache and 
    1107 /// tells to the working thread to render it. 
     1051/// creates a new job for rendering it. 
    11081052/// 
    11091053/// After adding the new page, if the cache size is larger that it should be, 
    11101054/// then this deletes the oldest request from the cache. 
    11111055/// 
    1112 /// @param pageNum The page number to render. 
    1113 /// 
    1114 void 
    1115 IDocument::scheduleToRender (gint pageNum) 
     1056/// @param pageNum The page number to add to the cache. 
     1057/// 
     1058void 
     1059IDocument::addPageToCache (gint pageNum) 
    11161060{ 
    11171061    // Check if the page is already on cache. 
    1118     PageRequest *request = NULL; 
    1119     for ( GList *cache = g_list_first (m_PageCache) ;  
    1120           NULL != cache && NULL == request ; 
    1121           cache = g_list_next (cache) ) 
    1122     { 
    1123         PageRequest *tmpRequest = (PageRequest *)cache->data; 
    1124         if ( pageNum == tmpRequest->pageNum ) 
    1125         { 
    1126             request = tmpRequest; 
    1127         } 
    1128     } 
    1129  
     1062    PageCache *cached = getCachedPage (pageNum); 
    11301063    // If it's not. 
    1131     if ( NULL == request ) 
     1064    if ( NULL == cached ) 
    11321065    { 
    11331066        //Create it. 
    1134         request = new PageRequest; 
    1135         request->pageNum = pageNum; 
    1136         request->page = new DocumentPage (); 
    1137         request->document = this; 
    1138         request->done = TRUE; 
    1139         request->age = m_PageCacheAge++; 
     1067        cached = new PageCache; 
     1068        cached->age = m_PageCacheAge++; 
     1069        cached->pageNumber = pageNum; 
     1070        cached->pageImage = NULL; 
     1071 
     1072        JobRender *job = new JobRender (); 
     1073        job->setDocument (this); 
     1074        job->setPageNumber (pageNum); 
     1075        IJob::queue (job); 
    11401076         
    11411077        // Check which cached page to drop. 
    11421078        if ( g_list_length (m_PageCache) >= CACHE_SIZE ) 
    11431079        { 
    1144             PageRequest *oldestRequest = NULL; 
     1080            PageCache *oldestCachedPage = NULL; 
    11451081            guint32 oldestAge = G_MAXUINT32; 
    1146             for ( GList *cache = g_list_first (m_PageCache) ; NULL != cache ; 
    1147                   cache = g_list_next (cache) ) 
     1082            for ( GList *page = g_list_first (m_PageCache) ; NULL != page ; 
     1083                  page = g_list_next (page) ) 
    11481084            { 
    1149                 PageRequest *tmpRequest = (PageRequest *)cache->data; 
    1150                 if ( tmpRequest->age < oldestAge ) 
     1085                PageCache *tmpCachedPage = (PageCache *)page->data; 
     1086                if ( tmpCachedPage->age < oldestAge ) 
    11511087                { 
    1152                     oldestAge = tmpRequest->age; 
    1153                     oldestRequest = tmpRequest; 
     1088                    oldestAge = tmpCachedPage->age; 
     1089                    oldestCachedPage = tmpCachedPage; 
    11541090                } 
    11551091            } 
    1156             m_PageCache = g_list_remove_all (m_PageCache, oldestRequest); 
    1157             WAIT_REQUEST (oldestRequest); 
    1158             delete oldestRequest->page; 
    1159             oldestRequest->page = NULL; 
    1160             delete oldestRequest; 
     1092            G_LOCK (JobRender); 
     1093            m_PageCache = g_list_remove_all (m_PageCache, oldestCachedPage); 
     1094            delete oldestCachedPage->pageImage; 
     1095            delete oldestCachedPage; 
     1096            G_UNLOCK (JobRender); 
    11611097        } 
    1162         // Add the page to the cache and render it. 
    1163         m_PageCache = g_list_append (m_PageCache, request); 
    1164         g_async_queue_push (m_RenderQueue, (gpointer)request); 
     1098        // Add the page to the cache. 
     1099        m_PageCache = g_list_append (m_PageCache, cached); 
    11651100    } 
    11661101    else 
    11671102    { 
    11681103        // If the page is already on cache, just update the age. 
    1169         request->age = m_PageCacheAge++; 
    1170     } 
     1104        cached->age = m_PageCacheAge++; 
     1105    } 
     1106} 
     1107 
     1108PageCache * 
     1109IDocument::getCachedPage (gint pageNum) 
     1110{ 
     1111    PageCache *cached = NULL; 
     1112    for ( GList *page = g_list_first (m_PageCache) ;  
     1113          NULL != page && NULL == cached ; 
     1114          page = g_list_next (page) ) 
     1115    { 
     1116        PageCache *tmpCached = (PageCache *)page->data; 
     1117        if ( pageNum == tmpCached->pageNumber ) 
     1118        { 
     1119            cached = tmpCached; 
     1120        } 
     1121    } 
     1122 
     1123    return cached; 
    11711124} 
    11721125 
     
    11801133IDocument::refreshCache () 
    11811134{ 
    1182     G_LOCK (rendering); 
    1183     for ( GList *cache = g_list_first (m_PageCache) ; NULL != cache ; 
    1184           cache = g_list_next (cache) ) 
    1185     { 
    1186         PageRequest *request = (PageRequest *)cache->data; 
    1187         if ( request->done ) 
    1188         { 
    1189             delete request->page; 
    1190             request->page = NULL; 
    1191             request->done = FALSE; 
    1192             g_async_queue_push (m_RenderQueue, (gpointer)request); 
    1193         } 
    1194     } 
    1195     G_UNLOCK (rendering); 
     1135    for ( GList *page = g_list_first (m_PageCache) ;  
     1136          NULL != page ; 
     1137          page = g_list_next (page) ) 
     1138    { 
     1139        PageCache *cachedPage = (PageCache *)page->data; 
     1140        delete cachedPage->pageImage; 
     1141        cachedPage->pageImage = NULL; 
     1142        JobRender *job = new JobRender; 
     1143        job->setDocument (this); 
     1144        job->setPageNumber (cachedPage->pageNumber); 
     1145        IJob::queue (job); 
     1146    } 
    11961147} 
    11971148 
     
    12051156IDocument::clearCache () 
    12061157{ 
    1207     // This will tell the working thread not to render them. 
    1208     G_UNLOCK (rendering); 
    1209     for ( GList *cache = g_list_first (m_PageCache) ; NULL != cache ; 
    1210           cache = g_list_next (cache) ) 
    1211     { 
    1212         PageRequest *request = (PageRequest *)cache->data; 
    1213         request->pageNum = 0; 
    1214     } 
    1215     G_UNLOCK (rendering); 
    1216  
    12171158    // Delete all cached pages. 
    1218     for ( GList *cache = g_list_first (m_PageCache) ; NULL != cache ; 
    1219           cache = g_list_next (cache) ) 
    1220     { 
    1221         PageRequest *request = (PageRequest *)cache->data; 
    1222         WAIT_REQUEST (request); 
    1223         delete request->page; 
    1224         request->page = NULL; 
    1225         delete request; 
     1159    for ( GList *page = g_list_first (m_PageCache) ;  
     1160          NULL != page ; 
     1161          page = g_list_next (page) ) 
     1162    { 
     1163        PageCache *cachedPage = (PageCache *)page->data; 
     1164        delete cachedPage->pageImage; 
     1165        delete cachedPage; 
    12261166    } 
    12271167    g_list_free (m_PageCache); 
  • trunk/src/IDocument.h

    r129 r130  
    106106    } PageLayout; 
    107107 
     108 
     109    typedef struct 
     110    { 
     111        guint32 age; 
     112        gint pageNumber; 
     113        DocumentPage *pageImage; 
     114    } PageCache; 
     115 
    108116    /// 
    109117    /// @class IDocument 
     
    181189            void notifyLoadPassword (const GError *error); 
    182190            void notifyPageChanged (void); 
     191            void notifyPageRendered (gint pageNumber, DocumentPage *pageImage); 
    183192            void notifyPageRotated (void); 
    184193            void notifyPageZoomed (void); 
     
    245254            static GQuark getErrorQuark (void); 
    246255            static gchar *getErrorMessage (DocumentError errorCode); 
    247             static gpointer renderPageWorker (gpointer data);  
    248256 
    249257        protected: 
     
    251259             
    252260            IDocument (void); 
    253             void scheduleToRender (gint pageNum); 
     261            void addPageToCache (gint pageNum); 
     262            PageCache *getCachedPage (gint pageNum); 
    254263            void refreshCache (void); 
    255264 
     
    276285            gchar *m_Subject; 
    277286            gchar *m_Title; 
    278             GAsyncQueue *m_RenderQueue; 
    279287    }; 
    280288} 
  • trunk/src/IJob.cxx

    r124 r130  
    2121 
    2222GAsyncQueue *IJob::m_JobsQueue = NULL; 
     23 
     24void 
     25IJob::clearQueue (void) 
     26{ 
     27    IJob *job = NULL; 
     28    do 
     29    { 
     30        job = (IJob *)g_async_queue_try_pop (m_JobsQueue); 
     31    } 
     32    while ( NULL != job ); 
     33} 
    2334 
    2435gpointer 
  • trunk/src/IJob.h

    r126 r130  
    3636            virtual ~IJob (void) { } 
    3737 
     38            static void clearQueue (void); 
    3839            static gpointer dispatcher (gpointer data);  
    3940            static void init (void); 
  • trunk/src/Makefile.am

    r124 r130  
    2020    JobLoad.cxx         \ 
    2121    JobLoad.h           \ 
     22    JobRender.cxx   \ 
     23    JobRender.h \ 
    2224    MainPter.cxx        \ 
    2325    MainPter.h          \ 
  • trunk/src/epdfview.h

    r124 r130  
    3535#include <IJob.h> 
    3636#include <JobLoad.h> 
     37#include <JobRender.h> 
    3738 
    3839#endif //!__E_PDF_VIEW_H__ 
  • trunk/tests/PDFDocumentTest.cxx

    r129 r130  
    2424static const double DELTA = 0.0001; 
    2525 
     26// Lock for rendering pages. 
     27G_LOCK_EXTERN (JobRender); 
     28 
    2629// Register the test suite into the `registry'. 
    2730CPPUNIT_TEST_SUITE_REGISTRATION (PDFDocumentTest); 
     
    3639    m_Observer = new DumbDocumentObserver (); 
    3740    m_Document->attach (m_Observer); 
     41    G_LOCK (JobRender); 
     42    JobRender::m_CanProcessJobs = TRUE; 
     43    G_UNLOCK (JobRender); 
    3844} 
    3945 
     
    4450PDFDocumentTest::tearDown () 
    4551{ 
     52    G_LOCK (JobRender); 
     53    JobRender::m_CanProcessJobs = FALSE; 
     54    IJob::clearQueue (); 
     55    G_UNLOCK (JobRender); 
    4656    m_Document->deattach (m_Observer); 
    4757    delete m_Observer; 
     
    541551    g_free (testFile); 
    542552} 
    543 /* 
     553 
    544554/// 
    545555/// @brief Test rendering a page. 
     
    573583    CPPUNIT_ASSERT_DOUBLES_EQUAL (0.3562f, m_Document->getZoom (), DELTA); 
    574584    DocumentPage *page = m_Document->getCurrentPage (); 
     585    CPPUNIT_ASSERT (NULL != page); 
    575586    CPPUNIT_ASSERT_EQUAL (300, page->getWidth ()); 
    576587    CPPUNIT_ASSERT_EQUAL (212, page->getHeight ()); 
     
    587598    g_free (testFile); 
    588599} 
    589 */ 
  • trunk/tests/PDFDocumentTest.h

    r129 r130  
    3535        CPPUNIT_TEST (pageRotate); 
    3636        CPPUNIT_TEST (pageZoom); 
    37 //        CPPUNIT_TEST (pageRender); 
     37        CPPUNIT_TEST (pageRender); 
    3838        CPPUNIT_TEST_SUITE_END (); 
    3939