Changeset 130
- Timestamp:
- 04/29/06 06:04:59 (2 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 8 modified
-
src/IDocument.cxx (modified) (15 diffs)
-
src/IDocument.h (modified) (5 diffs)
-
src/IJob.cxx (modified) (1 diff)
-
src/IJob.h (modified) (1 diff)
-
src/JobRender.cxx (added)
-
src/JobRender.h (added)
-
src/Makefile.am (modified) (1 diff)
-
src/epdfview.h (modified) (1 diff)
-
tests/PDFDocumentTest.cxx (modified) (6 diffs)
-
tests/PDFDocumentTest.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/IDocument.cxx
r129 r130 22 22 using namespace ePDFView; 23 23 24 G_LOCK_DEFINE_STATIC (rendering);25 #define WAIT_REQUEST(req) while (!req->done) { }26 27 24 // Constants. 28 25 static const gdouble ZOOM_IN_FACTOR = 1.2; … … 32 29 static const guint CACHE_SIZE = 3; 33 30 34 typedef struct35 {36 guint32 age;37 gint pageNum;38 IDocument *document;39 DocumentPage *page;40 volatile gboolean done;41 } PageRequest;42 43 31 /// This is the error domain that will be used to report Document's errors. 44 32 GQuark IDocument::errorQuark = 0; 33 34 G_LOCK_EXTERN (JobRender); 45 35 46 36 /// … … 128 118 129 119 /// 130 /// @brief Renders the requested pages.131 ///132 /// This is a working thread that waits until a request to render133 /// a page is make. Then it renders the requested page and waits134 /// for another.135 /// The IDocument class is responsable to make the requests.136 ///137 gpointer138 IDocument::renderPageWorker (gpointer data)139 {140 GAsyncQueue *renderQueue = (GAsyncQueue *)data;141 gboolean exit = FALSE;142 do143 {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 else152 {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 ///171 120 /// @brief Constructs a new IDocument object. 172 121 /// … … 195 144 m_Subject = NULL; 196 145 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);206 146 } 207 147 … … 211 151 IDocument::~IDocument () 212 152 { 213 // Create a page request with an invalid page number to let know the214 // 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 221 153 g_list_free (m_Observers); 222 154 delete m_Outline; … … 254 186 IDocument::notifyLoad () 255 187 { 188 // Add the two first pages to the cache. 189 addPageToCache (1); 190 addPageToCache (2); 191 256 192 for ( GList *item = g_list_first (m_Observers) ; NULL != item ; 257 193 item = g_list_next (item) ) … … 293 229 IDocumentObserver *observer = (IDocumentObserver *)item->data; 294 230 observer->notifyPageChanged (pageNum); 231 } 232 } 233 #include <stdio.h> 234 void 235 IDocument::notifyPageRendered (gint pageNumber, DocumentPage *pageImage) 236 { 237 PageCache *cachedPage = getCachedPage (pageNumber); 238 if ( NULL != cachedPage ) 239 { 240 delete cachedPage->pageImage; 241 cachedPage->pageImage = pageImage; 295 242 } 296 243 } … … 331 278 job->setFileName (fileName); 332 279 job->setPassword (password); 333 334 280 IJob::queue (job); 335 281 } … … 781 727 IDocument::getCurrentPage () 782 728 { 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 ) 796 731 { 797 732 return NULL; 798 733 } 799 WAIT_REQUEST (request); 800 return request->page; 734 735 while ( NULL == cachedPage->pageImage ) 736 { 737 ; 738 } 739 740 return cachedPage->pageImage; 801 741 } 802 742 … … 894 834 m_CurrentPage = pageNum; 895 835 896 scheduleToRender(m_CurrentPage);836 addPageToCache (m_CurrentPage); 897 837 if ( 1 < m_CurrentPage ) 898 838 { 899 scheduleToRender(m_CurrentPage - 1);839 addPageToCache (m_CurrentPage - 1); 900 840 } 901 841 if ( m_CurrentPage < getNumPages () ) 902 842 { 903 scheduleToRender(m_CurrentPage + 1);843 addPageToCache (m_CurrentPage + 1); 904 844 } 905 845 … … 943 883 if ( rotation != m_Rotation ) 944 884 { 885 G_LOCK (JobRender); 945 886 m_Rotation = (rotation % 360); 946 887 refreshCache (); 947 888 notifyPageRotated (); 889 G_UNLOCK (JobRender); 948 890 } 949 891 } … … 1017 959 IDocument::setZoom (gdouble zoom) 1018 960 { 1019 if ( ABS (zoom - m_Scale) > 0.00001 ) 1020 { 961 if ( ABS (zoom - m_Scale) > 0.00001 ) 962 { 963 G_LOCK (JobRender); 1021 964 m_Scale = zoom; 1022 965 refreshCache (); 1023 966 notifyPageZoomed (); 967 G_UNLOCK (JobRender); 1024 968 } 1025 969 } … … 1101 1045 1102 1046 /// 1103 /// @brief Adds a new page to be rendered.1047 /// @brief Adds a new page to the cache and starts to render it. 1104 1048 /// 1105 1049 /// This function checks if a page is already on the cache. If it is, then 1106 1050 /// only updates the age and returns. Otherwise adds the page to the cache and 1107 /// tells to the working thread to renderit.1051 /// creates a new job for rendering it. 1108 1052 /// 1109 1053 /// After adding the new page, if the cache size is larger that it should be, 1110 1054 /// then this deletes the oldest request from the cache. 1111 1055 /// 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 /// 1058 void 1059 IDocument::addPageToCache (gint pageNum) 1116 1060 { 1117 1061 // 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); 1130 1063 // If it's not. 1131 if ( NULL == request)1064 if ( NULL == cached ) 1132 1065 { 1133 1066 //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); 1140 1076 1141 1077 // Check which cached page to drop. 1142 1078 if ( g_list_length (m_PageCache) >= CACHE_SIZE ) 1143 1079 { 1144 Page Request *oldestRequest= NULL;1080 PageCache *oldestCachedPage = NULL; 1145 1081 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) ) 1148 1084 { 1149 Page Request *tmpRequest = (PageRequest *)cache->data;1150 if ( tmp Request->age < oldestAge )1085 PageCache *tmpCachedPage = (PageCache *)page->data; 1086 if ( tmpCachedPage->age < oldestAge ) 1151 1087 { 1152 oldestAge = tmp Request->age;1153 oldest Request = tmpRequest;1088 oldestAge = tmpCachedPage->age; 1089 oldestCachedPage = tmpCachedPage; 1154 1090 } 1155 1091 } 1156 m_PageCache = g_list_remove_all (m_PageCache, oldestRequest);1157 WAIT_REQUEST (oldestRequest);1158 delete oldest Request->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); 1161 1097 } 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); 1165 1100 } 1166 1101 else 1167 1102 { 1168 1103 // 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 1108 PageCache * 1109 IDocument::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; 1171 1124 } 1172 1125 … … 1180 1133 IDocument::refreshCache () 1181 1134 { 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 } 1196 1147 } 1197 1148 … … 1205 1156 IDocument::clearCache () 1206 1157 { 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 1217 1158 // 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; 1226 1166 } 1227 1167 g_list_free (m_PageCache); -
trunk/src/IDocument.h
r129 r130 106 106 } PageLayout; 107 107 108 109 typedef struct 110 { 111 guint32 age; 112 gint pageNumber; 113 DocumentPage *pageImage; 114 } PageCache; 115 108 116 /// 109 117 /// @class IDocument … … 181 189 void notifyLoadPassword (const GError *error); 182 190 void notifyPageChanged (void); 191 void notifyPageRendered (gint pageNumber, DocumentPage *pageImage); 183 192 void notifyPageRotated (void); 184 193 void notifyPageZoomed (void); … … 245 254 static GQuark getErrorQuark (void); 246 255 static gchar *getErrorMessage (DocumentError errorCode); 247 static gpointer renderPageWorker (gpointer data);248 256 249 257 protected: … … 251 259 252 260 IDocument (void); 253 void scheduleToRender (gint pageNum); 261 void addPageToCache (gint pageNum); 262 PageCache *getCachedPage (gint pageNum); 254 263 void refreshCache (void); 255 264 … … 276 285 gchar *m_Subject; 277 286 gchar *m_Title; 278 GAsyncQueue *m_RenderQueue;279 287 }; 280 288 } -
trunk/src/IJob.cxx
r124 r130 21 21 22 22 GAsyncQueue *IJob::m_JobsQueue = NULL; 23 24 void 25 IJob::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 } 23 34 24 35 gpointer -
trunk/src/IJob.h
r126 r130 36 36 virtual ~IJob (void) { } 37 37 38 static void clearQueue (void); 38 39 static gpointer dispatcher (gpointer data); 39 40 static void init (void); -
trunk/src/Makefile.am
r124 r130 20 20 JobLoad.cxx \ 21 21 JobLoad.h \ 22 JobRender.cxx \ 23 JobRender.h \ 22 24 MainPter.cxx \ 23 25 MainPter.h \ -
trunk/src/epdfview.h
r124 r130 35 35 #include <IJob.h> 36 36 #include <JobLoad.h> 37 #include <JobRender.h> 37 38 38 39 #endif //!__E_PDF_VIEW_H__ -
trunk/tests/PDFDocumentTest.cxx
r129 r130 24 24 static const double DELTA = 0.0001; 25 25 26 // Lock for rendering pages. 27 G_LOCK_EXTERN (JobRender); 28 26 29 // Register the test suite into the `registry'. 27 30 CPPUNIT_TEST_SUITE_REGISTRATION (PDFDocumentTest); … … 36 39 m_Observer = new DumbDocumentObserver (); 37 40 m_Document->attach (m_Observer); 41 G_LOCK (JobRender); 42 JobRender::m_CanProcessJobs = TRUE; 43 G_UNLOCK (JobRender); 38 44 } 39 45 … … 44 50 PDFDocumentTest::tearDown () 45 51 { 52 G_LOCK (JobRender); 53 JobRender::m_CanProcessJobs = FALSE; 54 IJob::clearQueue (); 55 G_UNLOCK (JobRender); 46 56 m_Document->deattach (m_Observer); 47 57 delete m_Observer; … … 541 551 g_free (testFile); 542 552 } 543 /* 553 544 554 /// 545 555 /// @brief Test rendering a page. … … 573 583 CPPUNIT_ASSERT_DOUBLES_EQUAL (0.3562f, m_Document->getZoom (), DELTA); 574 584 DocumentPage *page = m_Document->getCurrentPage (); 585 CPPUNIT_ASSERT (NULL != page); 575 586 CPPUNIT_ASSERT_EQUAL (300, page->getWidth ()); 576 587 CPPUNIT_ASSERT_EQUAL (212, page->getHeight ()); … … 587 598 g_free (testFile); 588 599 } 589 */ -
trunk/tests/PDFDocumentTest.h
r129 r130 35 35 CPPUNIT_TEST (pageRotate); 36 36 CPPUNIT_TEST (pageZoom); 37 //CPPUNIT_TEST (pageRender);37 CPPUNIT_TEST (pageRender); 38 38 CPPUNIT_TEST_SUITE_END (); 39 39
