00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <cassert>
00028 #include <iostream>
00029 #include "images_renderer.h"
00030 #include "image_render_task.h"
00031 #include "log.h"
00032
00033 namespace images
00034 {
00035
00036 static const int MAX_ORIGINAL_IMAGE = 10 * 1024 * 1024;
00037
00038
00039 ImagesRenderer::ImagesRenderer(ImagesDocument * document)
00040 : doc(document)
00041 , render_thread()
00042 , pages_cache()
00043 , last_render_page(0)
00044 {
00045 LOGPRINTF("%p", document);
00046
00047 render_thread.start();
00048
00049
00050 set_prerender_policy(2, 2);
00051 }
00052
00053 ImagesRenderer::~ImagesRenderer(void)
00054 {
00055 LOGPRINTF("entry");
00056
00057 render_thread.stop();
00058
00059 }
00060
00061 ImageRenderStatus ImagesRenderer::render(const std::string & anchor,
00062 const ImagePageAttrs & attrs,
00063 int ref_id,
00064 void * user_data)
00065 {
00066 LOGPRINTF("%s, zoom[%f], rotation[%d], ref_id[%d]",
00067 anchor.c_str(), attrs.zoom, attrs.rotation, ref_id);
00068
00069
00070 ImageRenderStatus ret = IMG_RENDER_OK;
00071
00072
00073 render_thread.clear_all();
00074
00075 ImageRenderTask * task = 0;
00076
00077
00078 ImagePage * page = get_page(anchor, attrs);
00079 if (!page)
00080 {
00081 ret = can_render(anchor, attrs);
00082 if (ret == IMG_RENDER_OK)
00083 {
00084
00085 task = new ImageRenderTask(anchor, attrs, ref_id, this, user_data);
00086
00087
00088
00089 render_thread.prepend_task(task, true);
00090 }
00091 else
00092 {
00093
00094 notify_page_ready(0, ref_id, ret, user_data);
00095 }
00096 }
00097 else
00098 {
00099 WARNPRINTF("Page %s already in pages_cache!", anchor.c_str());
00100
00101
00102
00103 notify_page_ready(page, ref_id, IMG_RENDER_OK, user_data);
00104 }
00105
00106
00107 assert(doc);
00108 int page_num = doc->get_position(anchor);
00109
00110 bool page_down = (last_render_page <= page_num) ? true : false;
00111 last_render_page = page_num;
00112 pre_render(page_num, attrs, page_down);
00113
00114 return ret;
00115 }
00116
00117 ImagePage * ImagesRenderer::get_page(const std::string & anchor,
00118 const ImagePageAttrs & attrs)
00119 {
00120 LOGPRINTF("%s zoom[%f] rotation[%d]",
00121 anchor.c_str(), attrs.zoom, attrs.rotation);
00122
00123 size_t key = ImagePage::calc_key(anchor,
00124 attrs.desired_width,
00125 attrs.desired_height,
00126 attrs.zoom,
00127 attrs.rotation);
00128
00129 ImagePage * page = pages_cache.get_page(key);
00130
00131 LOGPRINTF("return %p", page);
00132
00133 return page;
00134 }
00135
00136 void ImagesRenderer::add_page(ImagePage * page)
00137 {
00138 LOGPRINTF("%p", page);
00139
00140 if (page)
00141 {
00142 pages_cache.add_page(page);
00143 }
00144 }
00145
00146
00147
00148 ImageRenderStatus ImagesRenderer::can_render(const std::string & anchor,
00149 const ImagePageAttrs & attrs)
00150 {
00151 bool is_valid_image = false;
00152 if ((attrs.original_width > 0) && (attrs.original_height > 0))
00153 {
00154 is_valid_image = true;
00155 }
00156
00157
00158 if (!is_valid_image)
00159 {
00160 WARNPRINTF("Invalid image page %s.", anchor.c_str());
00161 return IMG_RENDER_INVALID;
00162 }
00163
00164
00165
00166
00167
00168 if (attrs.original_width * attrs.original_height > MAX_ORIGINAL_IMAGE)
00169 {
00170 WARNPRINTF("Image too big: w [%d] h [%d] max [%d]", attrs.original_width, attrs.original_height, MAX_ORIGINAL_IMAGE);
00171 return IMG_RENDER_FAIL;
00172 }
00173
00174
00175 gint64 size = ImagePage::estimate_length(attrs);
00176 if (!pages_cache.make_enough_memory(size))
00177 {
00178 LOGPRINTF("Not enough memory to render page [%s]", anchor.c_str());
00179 return IMG_RENDER_OOM;
00180 }
00181
00182 return IMG_RENDER_OK;
00183
00184 }
00185
00186 void ImagesRenderer::pre_render(int page_num,
00187 const ImagePageAttrs & attrs,
00188 bool page_down)
00189 {
00190 LOGPRINTF("%d page_down = %d", page_num, page_down);
00191
00192
00193
00194
00195
00196 if (page_down)
00197 {
00198 LOGPRINTF("Render the next pages firstly.");
00199 render_next_pages(page_num, attrs);
00200 render_prev_pages(page_num, attrs);
00201 }
00202 else
00203 {
00204 LOGPRINTF("Render the previous pages firstly.");
00205 render_prev_pages(page_num, attrs);
00206 render_next_pages(page_num, attrs);
00207 }
00208 }
00209
00210 void ImagesRenderer::render_prev_pages(int page_num,
00211 const ImagePageAttrs & attrs)
00212 {
00213
00214 int prev = page_num - prev_range_pages;
00215 if (prev < 1) { prev = 1; }
00216
00217 ImagePage * page = 0;
00218 ImageRenderTask * task = 0;
00219
00220 for (int i = page_num - 1; i >= prev; i--)
00221 {
00222 std::string anchor;
00223 if (doc->get_anchor_of_page(i, anchor))
00224 {
00225 page = get_page(anchor, attrs);
00226 if (!page)
00227 {
00228 if (can_render(anchor, attrs) == IMG_RENDER_OK)
00229 {
00230 task = new ImageRenderTask(anchor, attrs, -1, this, 0);
00231 render_thread.append_task(task);
00232 }
00233 }
00234 else
00235 {
00236 WARNPRINTF("Page %s already in pages_cache!", anchor.c_str());
00237 notify_page_ready(page, -1, IMG_RENDER_OK, 0);
00238 }
00239 }
00240 }
00241
00242 }
00243
00244 void ImagesRenderer::render_next_pages(int page_num,
00245 const ImagePageAttrs & attrs)
00246 {
00247
00248 int next = page_num + next_range_pages;
00249 if (next > ((int)doc->page_count()))
00250 {
00251 next = ((int)doc->page_count());
00252 }
00253
00254 ImagePage * page = 0;
00255 ImageRenderTask * task = 0;
00256
00257 for (int i = page_num + 1; i <= next; i++)
00258 {
00259 std::string anchor;
00260 if (doc->get_anchor_of_page(i, anchor))
00261 {
00262 page = get_page(anchor, attrs);
00263 if (!page)
00264 {
00265 if (can_render(anchor, attrs) == IMG_RENDER_OK)
00266 {
00267 task = new ImageRenderTask(anchor, attrs, -1, this, 0);
00268 render_thread.append_task(task);
00269 }
00270 }
00271 else
00272 {
00273 WARNPRINTF("Page %s already in pages_cache!", anchor.c_str());
00274 notify_page_ready(page, -1, IMG_RENDER_OK, 0);
00275 }
00276 }
00277 }
00278 }
00279
00280 void ImagesRenderer::notify_page_ready(ImagePage * page,
00281 int ref_id,
00282 ImageRenderStatus status,
00283 void * user_data)
00284 {
00285 LOGPRINTF("%p %d", page, ref_id);
00286
00287 pages_cache.lock();
00288
00289 if (page)
00290 {
00291 page->update_timestamp();
00292 }
00293
00294 if (ref_id != -1)
00295 {
00296 sig_page_ready.broadcast(page, ref_id, status, user_data);
00297 }
00298
00299 pages_cache.unlock();
00300 }
00301
00302 void ImagesRenderer::set_prerender_policy(int prev_range, int next_range)
00303 {
00304 LOGPRINTF("range[%d, %d]", prev_range, next_range);
00305
00306 prev_range_pages = prev_range;
00307 next_range_pages = next_range;
00308 }
00309
00310 bool ImagesRenderer::set_memory_limit(const int bytes)
00311 {
00312 LOGPRINTF("entry");
00313
00314 return pages_cache.set_memory_limit(bytes);
00315 }
00316
00317 void ImagesRenderer::stop(void)
00318 {
00319 render_thread.stop();
00320 }
00321
00322 };
00323
00324