Changeset 120

Show
Ignore:
Timestamp:
04/26/06 06:44:05 (2 years ago)
Author:
jordi
Message:

Added initial support for caching of page's pixmaps.

Location:
trunk
Files:
10 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/IDocument.cxx

    r85 r120  
    2222 
    2323// Constants. 
    24 static const gdouble ZOOM_IN_FACTOR = 1.2F; 
    25 static const gdouble ZOOM_IN_MAX = 4.0F; 
    26 static const gdouble ZOOM_OUT_FACTOR = (1.0F / ZOOM_IN_FACTOR); 
     24static const gdouble ZOOM_IN_FACTOR = 1.2; 
     25static const gdouble ZOOM_IN_MAX = 4.0; 
     26static const gdouble ZOOM_OUT_FACTOR = (1.0 / ZOOM_IN_FACTOR); 
    2727static const gdouble ZOOM_OUT_MAX = 0.05409; 
     28 
     29// This is the asynchronous queue for rendering. 
     30static guint currentCacheAge = 0; 
     31 
     32typedef struct 
     33{ 
     34    guint32 age; 
     35    gint pageNum; 
     36    IDocument *document; 
     37    DocumentPage *page; 
     38    gboolean done; 
     39} PageRequest; 
    2840 
    2941/// This is the error domain that will be used to report Document's errors. 
     
    114126 
    115127/// 
     128/// @brief Renders the requested pages. 
     129/// 
     130/// This is a working thread that waits until a request to render 
     131/// a page is make. Then it renders the requested page and waits 
     132/// for another. 
     133/// The IDocument class is responsable to make the requests. 
     134/// 
     135gpointer 
     136IDocument::renderPageWorker (gpointer data) 
     137{ 
     138    GAsyncQueue *renderQueue = (GAsyncQueue *)data; 
     139    gboolean exit = FALSE; 
     140    do 
     141    { 
     142        PageRequest *request = (PageRequest *)g_async_queue_pop (renderQueue); 
     143        if ( 0 < request->pageNum ) 
     144        { 
     145            request->page = request->document->renderPage (request->pageNum); 
     146            request->done = TRUE; 
     147        } 
     148        else if ( -1 == request->pageNum ) 
     149        { 
     150            delete request; 
     151            exit = TRUE; 
     152        } 
     153    } 
     154    while (!exit); 
     155 
     156    g_async_queue_unref (renderQueue); 
     157    renderQueue = NULL; 
     158     
     159    return NULL; 
     160} 
     161 
     162/// 
    116163/// @brief Constructs a new IDocument object. 
    117164/// 
     
    128175    m_Linearized = NULL; 
    129176    m_ModifiedDate = NULL; 
     177    m_PageCache = NULL; 
    130178    m_PageLayout = PageLayoutUnset; 
    131179    m_PageMode = PageModeUnset; 
     
    134182    m_Producer = NULL; 
    135183    m_Rotation = 0; 
    136     m_Scale = 0.0f; 
     184    m_Scale = 1.0f; 
    137185    m_Subject = NULL; 
    138186    m_Title = NULL; 
     187 
     188    if ( !g_thread_supported () ) 
     189    { 
     190        g_thread_init (NULL); 
     191    } 
     192    m_RenderQueue = g_async_queue_new (); 
     193    g_async_queue_ref (m_RenderQueue); 
     194    g_thread_create (IDocument::renderPageWorker, (gpointer)m_RenderQueue,  
     195                     FALSE, NULL); 
    139196} 
    140197 
     
    157214    g_free (m_Subject); 
    158215    g_free (m_Title); 
     216 
     217    // Create a page request with an invalid queue to let know the 
     218    // thread that we are done. 
     219    PageRequest *request = new PageRequest; 
     220    request->pageNum = -1; 
     221    g_async_queue_push (m_RenderQueue, (gpointer)request); 
     222    g_async_queue_unref (m_RenderQueue); 
    159223} 
    160224 
     
    598662 
    599663/// 
     664/// @brief Gets the document's current page image. 
     665/// 
     666/// @return The rendered image of the current page. 
     667/// 
     668DocumentPage * 
     669IDocument::getCurrentPage () 
     670{ 
     671    GList *cache = g_list_first (m_PageCache); 
     672    PageRequest *request = NULL; 
     673 
     674    while ( NULL != cache && NULL == request ) 
     675    { 
     676        PageRequest *tmpRequest = (PageRequest *)cache->data; 
     677        if ( m_CurrentPage == tmpRequest->pageNum ) 
     678        { 
     679            request = tmpRequest; 
     680        } 
     681        cache = g_list_next (cache); 
     682    } 
     683 
     684    if ( NULL == request ) 
     685        return NULL; 
     686 
     687    while ( !request->done ) 
     688    { 
     689    } 
     690 
     691    return request->page; 
     692} 
     693 
     694/// 
    600695/// @brief Get the document's current page number. 
    601696/// 
     
    620715{ 
    621716    return m_Outline; 
     717} 
     718 
     719/// 
     720/// @brief Gets the current page's unscaled size. 
     721/// 
     722/// Retrieves the width and height of the current page before to scale, but 
     723/// after rotation. 
     724///  
     725/// @param width The output pointer to save the page's width. 
     726/// @param height The output pointer to save the page's height. 
     727/// 
     728void 
     729IDocument::getPageSize (gdouble *width, gdouble *height) 
     730{ 
     731    getPageSizeForPage (getCurrentPageNum (), width, height); 
    622732} 
    623733 
     
    671781IDocument::goToPage (gint pageNum) 
    672782{ 
    673     if ( pageNum > getNumPages () ) 
    674     { 
    675         pageNum = getNumPages (); 
    676     } 
    677     else if ( pageNum < 1 ) 
    678     { 
    679         pageNum = 1; 
    680     } 
    681  
    682     m_CurrentPage = pageNum; 
     783    m_CurrentPage = CLAMP (pageNum, 1, getNumPages ()); 
     784 
     785    if ( 1 < m_CurrentPage ) 
     786    { 
     787        scheduleToRender (m_CurrentPage - 1); 
     788    } 
     789    scheduleToRender (m_CurrentPage); 
     790    if ( m_CurrentPage < getNumPages () ) 
     791    { 
     792        scheduleToRender (m_CurrentPage); 
     793    } 
    683794} 
    684795 
     
    717828{ 
    718829    m_Rotation = (rotation % 360); 
     830    refreshCache (); 
    719831} 
    720832 
     
    788900{ 
    789901    m_Scale = zoom; 
     902    refreshCache (); 
    790903} 
    791904 
     
    864977    setZoom ((gdouble)width / pageWidth); 
    865978} 
     979 
     980void 
     981IDocument::scheduleToRender (gint pageNum) 
     982{ 
     983    PageRequest *request = NULL; 
     984    GList *cache = g_list_first (m_PageCache); 
     985 
     986    while ( NULL != cache && NULL == request) 
     987    { 
     988        PageRequest *tmpRequest = (PageRequest *)cache->data; 
     989        if ( pageNum == tmpRequest->pageNum ) 
     990        { 
     991            request = tmpRequest; 
     992        } 
     993        cache = g_list_next (cache); 
     994    } 
     995 
     996    if ( NULL == request ) 
     997    { 
     998        request = new PageRequest; 
     999        request->pageNum = pageNum; 
     1000        request->page = NULL; 
     1001        request->document = this; 
     1002        request->done = FALSE; 
     1003        request->age = currentCacheAge++; 
     1004 
     1005        g_async_queue_push (m_RenderQueue, (gpointer)request); 
     1006 
     1007        // Check which cached page to drop. 
     1008        cache = g_list_first (m_PageCache); 
     1009        PageRequest *olderRequest = NULL; 
     1010        guint32 olderAge = G_MAXUINT32; 
     1011        gint numCaches = 0; 
     1012        while ( NULL != cache ) 
     1013        { 
     1014            numCaches++; 
     1015            PageRequest *tmpRequest = (PageRequest *)cache->data; 
     1016            if ( tmpRequest->age < olderAge ) 
     1017            { 
     1018                olderAge = tmpRequest->age; 
     1019                olderRequest = tmpRequest; 
     1020            } 
     1021            cache = g_list_next (cache); 
     1022        } 
     1023 
     1024        m_PageCache = g_list_append (m_PageCache, request); 
     1025        if ( 3 <= numCaches ) 
     1026        {             
     1027            m_PageCache = g_list_remove (m_PageCache, olderRequest); 
     1028            delete olderRequest->page; 
     1029            delete olderRequest; 
     1030        } 
     1031    } 
     1032    else 
     1033    { 
     1034        request->age = currentCacheAge++; 
     1035    } 
     1036} 
     1037 
     1038void 
     1039IDocument::refreshCache () 
     1040{ 
     1041    GList *cache = g_list_first (m_PageCache); 
     1042    while ( NULL != cache ) 
     1043    { 
     1044        PageRequest *request = (PageRequest *)cache->data; 
     1045 /*       while ( !request->done ) 
     1046        { 
     1047        }*/ 
     1048        request->done = FALSE; 
     1049        g_async_queue_push (m_RenderQueue, (gpointer)request); 
     1050        cache = g_list_next (cache); 
     1051    } 
     1052} 
  • trunk/src/IDocument.h

    r78 r120  
    148148                                       GError **error) = 0; 
    149149            /// 
    150             /// @brief Gets the current page's unscaled size. 
    151             /// 
    152             /// Retrieves the width and height of the current page before 
     150            /// @brief Gets a document's page's unscaled size. 
     151            /// 
     152            /// Retrieves the width and height of a document's page before 
    153153            /// scaling, but after rotate it. 
    154154            /// 
     155            /// @param pageNum The page to get its size. 
    155156            /// @param width The location to save the page's width. 
    156157            /// @param height The location to save the page's height. 
    157158            /// 
    158             virtual void getPageSize (gdouble *width, gdouble *height) = 0; 
    159  
    160             /// 
    161             /// @brief Renders the current page. 
    162             /// 
    163             /// Rendering the current page means to get the pixels for the 
    164             /// current page image given the current rotation and scale level. 
     159            virtual void getPageSizeForPage (gint pageNum, gdouble *width,  
     160                                             gdouble *height) = 0; 
     161 
     162            /// 
     163            /// @brief Renders a document's page. 
     164            /// 
     165            /// Rendering a document's page means to get the pixels for the 
     166            /// page image given the current rotation and scale level. 
     167            /// 
     168            /// @param pageNum The page number to render. 
    165169            /// 
    166170            /// @return A DocumentPage with the image. The returned page must 
    167171            ///         be freed by calling delete when done with it. 
    168172            /// 
    169             virtual DocumentPage *renderPage (void) = 0; 
     173            virtual DocumentPage *renderPage (gint pageNum) = 0; 
    170174 
    171175             
     
    198202            PageLayout getPageLayout (void); 
    199203            void setPageLayout (PageLayout layout); 
     204            void getPageSize (gdouble *width, gdouble *height); 
    200205            gint getNumPages (void); 
    201206            void setNumPages (gint numPages); 
     207            DocumentPage *getCurrentPage (void); 
    202208            gint getCurrentPageNum (void); 
    203209            DocumentOutline *getOutline (void); 
     
    225231            static GQuark getErrorQuark (void); 
    226232            static gchar *getErrorMessage (DocumentError errorCode); 
     233            static gpointer renderPageWorker (gpointer data);  
    227234 
    228235        protected: 
     
    230237             
    231238            IDocument (void); 
     239            void scheduleToRender (gint pageNum); 
     240            void refreshCache (void); 
    232241 
    233242            gchar *m_Author; 
     
    235244            gchar *m_Creator; 
    236245            gint m_CurrentPage; 
    237             DocumentOutline *m_Outline; 
    238246            gchar *m_Format; 
    239247            gchar *m_FileName; 
     
    241249            gchar *m_Linearized; 
    242250            gchar *m_ModifiedDate; 
     251            DocumentOutline *m_Outline; 
     252            GList *m_PageCache; 
    243253            PageLayout m_PageLayout; 
    244254            PageMode m_PageMode; 
     
    250260            gchar *m_Subject; 
    251261            gchar *m_Title; 
     262            GAsyncQueue *m_RenderQueue; 
    252263    }; 
    253264} 
  • trunk/src/MainPter.cxx

    r119 r120  
    2828{ 
    2929    m_Document = new PDFDocument (); 
    30     m_DocumentPage = NULL; 
    3130    m_View = NULL; 
    3231} 
     
    4443 
    4544    m_Document = document; 
    46     m_DocumentPage = NULL; 
    4745    m_View = NULL; 
    4846} 
     
    5553    delete m_Document; 
    5654    delete m_View; 
    57     delete m_DocumentPage; 
    5855} 
    5956 
     
    662659    view.sensitiveZoomOut (m_Document->canZoomOut ()); 
    663660     
    664     DocumentPage *oldPage = m_DocumentPage; 
    665     m_DocumentPage = m_Document->renderPage (); 
    666     if ( NULL != m_DocumentPage ) 
    667     { 
    668         getView ().showPage (m_DocumentPage, pageScroll); 
    669     } 
    670     delete oldPage; 
    671 } 
     661    DocumentPage *documentPage = m_Document->getCurrentPage (); 
     662    if ( NULL != documentPage ) 
     663    { 
     664        getView ().showPage (documentPage, pageScroll); 
     665    } 
     666} 
  • trunk/src/MainPter.h

    r115 r120  
    7171 
    7272            IDocument *m_Document; 
    73             DocumentPage *m_DocumentPage; 
    7473            IMainView *m_View; 
    7574 
  • trunk/src/PDFDocument.cxx

    r91 r120  
    279279 
    280280/// 
    281 /// @brief Gets the current page's unscaled size. 
    282 /// 
    283 /// Retrieves the width and height of the current page before to scale, but 
     281/// @brief Gets a document's page's unscaled size. 
     282/// 
     283/// Retrieves the width and height of a document's page before to scale, but 
    284284/// after rotation. 
    285285///  
     286/// @param pageNum The page to get its size. 
    286287/// @param width The output pointer to save the page's width. 
    287288/// @param height The output pointer to save the page's height. 
    288289/// 
    289290void 
    290 PDFDocument::getPageSize (gdouble *width, gdouble *height) 
     291PDFDocument::getPageSizeForPage (gint pageNum, gdouble *width, gdouble *height) 
    291292{ 
    292293    g_assert (NULL != m_Document && "Tried to get size of a NULL document."); 
     
    294295    g_assert (NULL != height && "Tried to save the page's height to NULL."); 
    295296 
    296     PopplerPage *page = poppler_document_get_page (m_Document, 
    297                                                    getCurrentPageNum () - 1); 
     297    PopplerPage *page = poppler_document_get_page (m_Document, pageNum - 1); 
    298298 
    299299    gdouble pageWidth; 
     
    316316 
    317317/// 
    318 /// @brief Renders the current page. 
    319 /// 
    320 /// Rendering the current page means to get the pixels for the current page, 
     318/// @brief Renders a document's page. 
     319/// 
     320/// Rendering a document's page means to get the pixels for the page, 
    321321/// given the current rotation level and scale. 
     322/// 
     323/// @param pageNum The page to render. 
    322324/// 
    323325/// @return A DocumentPage with the image. The returned page must be freed 
     
    325327/// 
    326328DocumentPage * 
    327 PDFDocument::renderPage () 
     329PDFDocument::renderPage (gint pageNum) 
    328330{ 
    329331    // First create the document's page. 
    330332    gdouble pageWidth; 
    331333    gdouble pageHeight; 
    332     getPageSize (&pageWidth, &pageHeight); 
     334    getPageSizeForPage (pageNum, &pageWidth, &pageHeight); 
    333335    gint width = MAX((gint) ((pageWidth * getZoom ()) + 0.5), 1); 
    334336    gint height = MAX((gint) ((pageHeight * getZoom ()) + 0.5), 1); 
     
    344346                                                  renderedPage->getRowStride (), 
    345347                                                  NULL, NULL); 
    346     PopplerPage *page = poppler_document_get_page (m_Document,  
    347                                                    getCurrentPageNum () - 1); 
     348    PopplerPage *page = poppler_document_get_page (m_Document, pageNum - 1); 
    348349    poppler_page_render_to_pixbuf (page, 0, 0, width, height, getZoom (), 
    349350                                   getRotation (), pixbuf); 
  • trunk/src/PDFDocument.h

    r78 r120  
    4141            gboolean loadFile (const gchar *filename, const gchar *password,  
    4242                           GError **error); 
    43             void getPageSize (gdouble *width, gdouble *height); 
    44             DocumentPage *renderPage (void); 
     43            void getPageSizeForPage (gint pageNum, gdouble *width,  
     44                                     gdouble *height); 
     45            DocumentPage *renderPage (gint pageNum); 
    4546 
    4647        protected: 
  • trunk/tests/DumbDocument.cxx

    r104 r120  
    7575 
    7676void 
    77 DumbDocument::getPageSize (gdouble *width, gdouble *height) 
     77DumbDocument::getPageSizeForPage (gint pageNum, gdouble *width, gdouble *height) 
    7878{ 
    7979    if ( 90 == getRotation () || 270 == getRotation () ) 
     
    9090 
    9191DocumentPage * 
    92 DumbDocument::renderPage () 
     92DumbDocument::renderPage (gint pageNum) 
    9393{ 
    9494    return new DocumentPage (); 
  • trunk/tests/DumbDocument.h

    r66 r120  
    3131            gboolean loadFile (const gchar *filename, const gchar *password, 
    3232                               GError **error); 
    33             void getPageSize (gdouble *width, gdouble *height); 
    34             DocumentPage *renderPage (void); 
     33            void getPageSizeForPage (gint pageNum, gdouble *width,  
     34                                     gdouble *height); 
     35            DocumentPage *renderPage (gint pageNum); 
    3536 
    3637            // Test functions. 
  • trunk/tests/MainPterTest.cxx

    </
    r115 r120  
    100100    m_MainPter->openFileActivated (); 
    101101    // Sleep to let the thread open the file. 
    102     sleep (1); 
     102    usleep (500); 
    103103    CPPUNIT_ASSERT_EQUAL (0,  
    104104            g_ascii_strcasecmp ("/tmp/test.pdf", m_View->getTitle ())); 
     
    122122    m_MainPter->openFileActivated (); 
    123123    // Sleep to let the thread open the file. 
    124     sleep (1); 
     124    usleep (500); 
    125125    CPPUNIT_ASSERT_EQUAL (0,  
    126126            g_ascii_strcasecmp ("Test PDF", m_View->getTitle ())); 
     
    153153    m_MainPter->openFileActivated (); 
    154154    // Sleep to let the thread open the file. 
    155     sleep (1); 
     155    usleep (500); 
    156156    CPPUNIT_ASSERT_EQUAL (0,  
    157157            g_ascii_strcasecmp ("PDF Viewer", m_View->getTitle ())); 
     
    186186    m_MainPter->openFileActivated (); 
    187187    // Sleep to let the thread open the file. 
    188     sleep (1); 
     188    usleep (500); 
    189189    CPPUNIT_ASSERT_EQUAL (0,  
    190190            g_ascii_strcasecmp ("PDF Viewer", m_View->getTitle ())); 
     
    221221    m_MainPter->openFileActivated (); 
    222222    // Sleep to let the thread open the file. 
    223     sleep (1); 
     223    usleep (500); 
    224224    CPPUNIT_ASSERT_EQUAL (0,  
    225225            g_ascii_strcasecmp ("PDF Viewer", m_View->getTitle ())); 
     
    256256    m_MainPter->openFileActivated (); 
    257257    // Sleep to let the thread open the file. 
    258     sleep (1); 
     258    usleep (500); 
    259259    CPPUNIT_ASSERT_EQUAL (0,  
    260260            g_ascii_strcasecmp ("PDF Viewer", m_View->getTitle ())); 
     
    291291    m_MainPter->openFileActivated (); 
    292292    // Sleep to let the thread open the file. 
    293     sleep (1); 
     293    usleep (500); 
    294294    CPPUNIT_ASSERT_EQUAL (0,  
    295295            g_ascii_strcasecmp ("/tmp/test.pdf", m_View->getTitle ())); 
     
    324324    m_MainPter->openFileActivated (); 
    325325    // Sleep to let the thread open the file. 
    326     sleep (1); 
     326    usleep (500); 
    327327    CPPUNIT_ASSERT (NULL == m_View->getLastOpenFileFolder ()); 
    328328 
     
    331331    m_MainPter->openFileActivated (); 
    332332    // Sleep to let the thread open the file. 
    333     sleep (1); 
     333    usleep (500); 
    334334    CPPUNIT_ASSERT (0 == g_ascii_strcasecmp ("/tmp",  
    335335                                             m_View->getLastOpenFileFolder ())); 
     
    337337    m_MainPter->openFileActivated (); 
    338338    // Sleep to let the thread open the file. 
    339     sleep (1); 
     339    usleep (500); 
    340340    CPPUNIT_ASSERT (0 == g_ascii_strcasecmp ("/usr",  
    341341                                             m_View->getLastOpenFileFolder ())); 
     
    355355    m_MainPter->openFileActivated (); 
    356356    // Sleep to let the thread open the file. 
    357     sleep (1); 
     357    usleep (500); 
    358358    // Check that sets the correct number of pages and the current page. 
    359359    CPPUNIT_ASSERT_EQUAL (4, m_View->getTotalPages ()); 
     
    437437    m_MainPter->openFileActivated (); 
    438438    // Sleep to let the thread open the file. 
    439     sleep (1); 
     439    usleep (500); 
    440440    // Check that sets the correct number of pages and the current page. 
    441441    CPPUNIT_ASSERT_EQUAL (4, m_View->getTotalPages ()); 
     
    518518    m_MainPter->openFileActivated (); 
    519519    // Sleep to let the thread open the file. 
    520     sleep (1); 
     520    usleep (500); 
    521521    CPPUNIT_ASSERT (m_View->hasImagePageView ()); 
    522522    CPPUNIT_ASSERT (!m_View->hasImagePageView ()); 
     
    548548    m_MainPter->openFileActivated (); 
    549549    // Sleep to let the thread open the file. 
    550     sleep (1); 
     550    usleep (500); 
    551551    CPPUNIT_ASSERT (m_View->hasImagePageView ()); 
    552552    CPPUNIT_ASSERT (!m_View->hasImagePageView ()); 
     
    589589    m_MainPter->openFileActivated (); 
    590590    // Sleep to let the thread open the file. 
    591     sleep (1); 
     591    usleep (500); 
    592592    CPPUNIT_ASSERT (m_View->hasImagePageView ());