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 "pdf_renderer.h"
00028 #include "pdf_doc_controller.h"
00029 #include "pdf_anchor.h"
00030 #include "pdf_render_task.h"
00031 #include "pdf_library.h"
00032 #include "log.h"
00033
00034 namespace pdf
00035 {
00036
00037 SplashColor PDFRenderer::background_color = {255, 255, 255, 0};
00038
00039 PDFRenderer::PDFRenderer()
00040 : doc_controller(0)
00041 , splash_output_dev(0)
00042 , text_output_dev(0)
00043 , thumbnail_output_dev(0)
00044 , view_attr()
00045 , cur_render_attr()
00046 , render_mutex()
00047 {
00048 }
00049
00050 PDFRenderer::~PDFRenderer(void)
00051 {
00052 destroy();
00053 }
00054
00055 bool PDFRenderer::initialize(PDFController* doc)
00056 {
00057
00058 destroy();
00059
00060 doc_controller = doc;
00061
00062 if (doc_controller == 0)
00063 {
00064 ERRORPRINTF("Null Document Controller");
00065 return false;
00066 }
00067
00068 SplashColorMode mode = splashModeMono8;
00069
00070
00071 splash_output_dev = new SplashOutputDev(mode, 4, gFalse, PDFRenderer::background_color);
00072 if (splash_output_dev == 0)
00073 {
00074 ERRORPRINTF("Cannot Open Splash Output Device");
00075 return false;
00076 }
00077
00078
00079 splash_output_dev->startDoc(doc_controller->get_pdf_doc()->getXRef());
00080
00081
00082 text_output_dev = new TextOutputDev(NULL, gTrue, gFalse, gFalse);
00083 if (text_output_dev == 0)
00084 {
00085 ERRORPRINTF("Cannot Open Text Output Device");
00086 return false;
00087 }
00088
00089
00090 thumbnail_output_dev = new SplashOutputDev(mode, 4, gFalse, PDFRenderer::background_color);
00091 if (thumbnail_output_dev == 0)
00092 {
00093 ERRORPRINTF("Cannot Open Thumbnail Output Device");
00094 return false;
00095 }
00096
00097 thumbnail_output_dev->startDoc(doc_controller->get_pdf_doc()->getXRef());
00098
00099 init_pages_index_table();
00100
00101 return true;
00102
00103 }
00104
00105 void PDFRenderer::destroy()
00106 {
00107 delete splash_output_dev;
00108 splash_output_dev = 0;
00109
00110 delete text_output_dev;
00111 text_output_dev = 0;
00112
00113 delete thumbnail_output_dev;
00114 thumbnail_output_dev = 0;
00115 }
00116
00117 void PDFRenderer::init_pages_index_table()
00118 {
00119
00120 doc_controller->clear_cache();
00121
00122 unsigned int num = doc_controller->page_count();
00123 for (unsigned int i = 1; i <= num; ++i)
00124 {
00125
00126 gen_page(i);
00127 }
00128 }
00129
00130 void PDFRenderer::calc_real_zoom(int page_number,
00131 const PDFRenderAttributes &origin_attr,
00132 PDFRenderAttributes &real_attr)
00133 {
00134 if (doc_controller == 0)
00135 {
00136 ERRORPRINTF("Serious Problem, Null Document Controller");
00137 return;
00138 }
00139
00140 real_attr = origin_attr;
00141 double real_zoom = origin_attr.get_zoom_setting();
00142
00143 if (real_zoom < 0)
00144 {
00145 double crop_width = doc_controller->get_page_crop_width(page_number);
00146 double crop_height = doc_controller->get_page_crop_height(page_number);
00147
00148 int display_width = doc_controller->get_display_width();
00149 int display_height = doc_controller->get_display_height();
00150
00151
00152 double zoom_v = 0.0f, zoom_h = 0.0f;
00153 if (real_zoom == PLUGIN_ZOOM_TO_PAGE ||
00154 real_zoom == PLUGIN_ZOOM_TO_WIDTH)
00155 {
00156 if (real_attr.get_rotate() == Clockwise_Degrees_90 ||
00157 real_attr.get_rotate() == Clockwise_Degrees_270)
00158 {
00159 std::swap(crop_height, crop_width);
00160 }
00161
00162 zoom_v = static_cast<double>(display_height) * 100 / crop_height;
00163 zoom_h = static_cast<double>(display_width) * 100 / crop_width;
00164
00165 if (real_zoom == PLUGIN_ZOOM_TO_PAGE)
00166 {
00167
00168 real_zoom = min(zoom_v, zoom_h);
00169 }
00170 else
00171 {
00172
00173 real_zoom = zoom_h;
00174 }
00175 }
00176 else if (real_zoom == PLUGIN_ZOOM_TO_CROP_BY_PAGE ||
00177 real_zoom == PLUGIN_ZOOM_TO_CROP_BY_WIDTH)
00178 {
00179
00180 PagePtr page = doc_controller->get_page(page_number);
00181 if (page != 0 && is_render_area_valid(page->get_content_area()))
00182 {
00183
00184 PluginRectangle rect;
00185 get_content_area_in_pixel(page->get_content_area(),
00186 crop_width, crop_height, rect);
00187
00188 crop_width = rect.width;
00189 crop_height = rect.height;
00190 if (real_attr.get_rotate() == Clockwise_Degrees_90 ||
00191 real_attr.get_rotate() == Clockwise_Degrees_270)
00192 {
00193 std::swap(crop_height, crop_width);
00194 }
00195
00196 zoom_v = static_cast<double>(display_height) * 100 / crop_height;
00197 zoom_h = static_cast<double>(display_width) * 100 / crop_width;
00198
00199 if (real_zoom == PLUGIN_ZOOM_TO_CROP_BY_PAGE)
00200 {
00201 real_zoom = min(zoom_v, zoom_h);
00202 }
00203 else
00204 {
00205 real_zoom = zoom_h;
00206 }
00207 }
00208 }
00209 }
00210
00211 real_attr.set_real_zoom_value(real_zoom);
00212 }
00213
00214 bool PDFRenderer::render_cover_page(const int width, const int height
00215 , PluginBitmapAttributes *output)
00216 {
00217 if (doc_controller->page_count() < 1)
00218 {
00219
00220 return false;
00221 }
00222
00223 int cover_num = 1;
00224
00225 double crop_width = doc_controller->get_page_crop_width(cover_num);
00226 double crop_height = doc_controller->get_page_crop_height(cover_num);
00227
00228 double zoom = min(static_cast<double>(width) / crop_width,
00229 static_cast<double>(height) / crop_height);
00230
00231
00232
00233 ScopeMutex m(&render_mutex);
00234
00235 RenderRet ret = doc_controller->get_pdf_doc()->displayPage(
00236 get_thumbnail_output_dev()
00237 , cover_num
00238 , zoom * get_view_attr().get_device_dpi_h()
00239 , zoom * get_view_attr().get_device_dpi_v()
00240 , 0
00241 , gFalse
00242 , gFalse
00243 , gFalse
00244 );
00245
00246 if (ret == Render_Error || ret == Render_Invalid)
00247 {
00248 ERRORPRINTF("Error in rendering cover page:%d\n", cover_num);
00249 return false;
00250 }
00251
00252 SplashBitmap *cover_map = get_thumbnail_output_dev()->takeBitmap();
00253 if (cover_map != 0)
00254 {
00255 memcpy((void*)output->data, cover_map->getDataPtr(),
00256 cover_map->getRowSize() * cover_map->getHeight());
00257 delete cover_map;
00258 return true;
00259 }
00260
00261 return false;
00262 }
00263
00264 void PDFRenderer::post_prerender_task(const size_t page_number,
00265 const PDFRenderAttributes &page_attr)
00266 {
00267 PDFRenderAttributes real_attr;
00268
00269 calc_real_zoom(page_number, page_attr, real_attr);
00270
00271
00272 PagePtr page = doc_controller->get_page(page_number);
00273 PDFRenderTask *task = 0;
00274 if (page)
00275 {
00276 if (!(page->get_render_attr() == page_attr) ||
00277 page->get_render_status() == PDFPage::RENDER_STOP)
00278 {
00279
00280
00281 task = gen_render_task(page, real_attr);
00282 }
00283 }
00284 else
00285 {
00286
00287 task = gen_render_task(page_number, real_attr);
00288 }
00289
00290 if (task != 0)
00291 {
00292 PDFLibrary::instance().thread_add_render_task(task, true, false);
00293 }
00294 }
00295
00296 void PDFRenderer::post_prerender_hyperlinks_task(PagePtr page)
00297 {
00298 if (page == 0)
00299 {
00300 ERRORPRINTF("Invalid page when posting hyperlink rendering task");
00301 return;
00302 }
00303
00304 Links *links = page->get_links();
00305
00306 if (links == 0)
00307 {
00308 return;
00309 }
00310
00311 int link_num = links->getNumLinks();
00312 if (link_num <= 0 ||
00313 link_num > doc_controller->get_prerender_policy()->get_allowed_hyperlinks_number())
00314 {
00315 return;
00316 }
00317
00318 link_num = doc_controller->get_prerender_policy()->get_allowed_hyperlinks_number();
00319 PDFRenderAttributes real_attr;
00320 for (int i = 0; i < link_num; i++)
00321 {
00322 int goto_page_num = page->get_goto_page_of_link(i);
00323 if (goto_page_num <= 0)
00324 {
00325
00326 continue;
00327 }
00328
00329
00330 calc_real_zoom(goto_page_num, page->get_render_attr(), real_attr);
00331
00332
00333 PagePtr goto_page = doc_controller->get_page(goto_page_num);
00334 PDFRenderTask* task = 0;
00335 if (goto_page)
00336 {
00337 if (!(goto_page->get_render_attr() == page->get_render_attr()) ||
00338 goto_page->get_render_status() == PDFPage::RENDER_STOP)
00339 {
00340 task = gen_render_task(goto_page, real_attr);
00341 }
00342 }
00343 else
00344 {
00345
00346 task = gen_render_task(goto_page_num, real_attr);
00347 }
00348
00349 if (task != 0)
00350 {
00351
00352 doc_controller->get_prerender_policy()->get_requests().append_request(goto_page_num);
00353 PDFLibrary::instance().thread_add_render_task(task, true, false);
00354 }
00355 }
00356 }
00357
00358 void PDFRenderer::post_render_task(int page_num,
00359 const PDFRenderAttributes &render_attr,
00360 PluginRenderResultImpl *render_res,
00361 const unsigned int ref_id)
00362 {
00363 if (page_num <= 0 || page_num > static_cast<int>(doc_controller->page_count()))
00364 {
00365 handle_page_ready(render_res, 0, TASK_RENDER_INVALID_PAGE);
00366 return;
00367 }
00368
00369
00370 int last_page = doc_controller->get_cur_page_num();
00371 doc_controller->set_cur_page_num(page_num);
00372
00373 PDFRenderAttributes real_attr;
00374 calc_real_zoom(page_num, render_attr, real_attr);
00375
00376 cur_render_attr = real_attr;
00377
00378
00379
00380 std::vector<size_t> requests;
00381 doc_controller->get_prerender_policy()->generate_requests_list(page_num,
00382 last_page,
00383 doc_controller->page_count(),
00384 requests);
00385
00386
00387 PagePtr page = doc_controller->get_page(page_num);
00388 PDFRenderTask* render_task = 0;
00389 bool abort_current_task = true;
00390 if (page)
00391 {
00392 {
00393 ScopeMutex m(&(doc_controller->get_pages_cache().get_mutex()));
00394 if (page->get_render_attr() == cur_render_attr)
00395 {
00396 if (page->get_render_status() == PDFPage::RENDER_DONE &&
00397 render_res != 0)
00398 {
00399
00400
00401 page->set_ref_id(ref_id);
00402 render_res->set_page(page);
00403 }
00404 else
00405 {
00406
00407 render_task = gen_render_task(page,
00408 real_attr,
00409 render_res,
00410 ref_id);
00411 if (page->get_render_status() == PDFPage::RENDER_RUNNING)
00412 {
00413 abort_current_task = false;
00414 }
00415 }
00416 }
00417 else
00418 {
00419 render_task = gen_render_task(page,
00420 real_attr,
00421 render_res,
00422 ref_id);
00423 }
00424 }
00425 }
00426 else
00427 {
00428
00429 render_task = gen_render_task(page_num,
00430 real_attr,
00431 render_res,
00432 ref_id);
00433 }
00434
00435 if (render_task != 0)
00436 {
00437 LOGPRINTF("PDF tries to render page:%d zoom:%f\n\n",
00438 page_num,
00439 real_attr.get_zoom_setting());
00440
00441
00442 PDFLibrary::instance().thread_cancel_render_tasks(render_task->get_user_data());
00443
00444
00445 PDFLibrary::instance().thread_add_render_task(render_task,
00446 false,
00447 abort_current_task);
00448 }
00449 else if (page != 0 && render_res != 0 &&
00450 page->get_render_status() == PDFPage::RENDER_DONE)
00451 {
00452
00453 handle_page_ready(render_res, page, TASK_RENDER_DONE);
00454 }
00455
00456
00457
00458 for (size_t idx = 1; idx < requests.size(); ++idx)
00459 {
00460 int dst_page = requests.at(idx);
00461 post_prerender_task(dst_page, render_attr);
00462 }
00463 }
00464
00465 void PDFRenderer::handle_page_ready(PluginRenderResultImpl *render_res,
00466 PagePtr page,
00467 RenderStatus stat)
00468 {
00469 switch (stat)
00470 {
00471 case TASK_RENDER_DONE:
00472 {
00473 if (page == 0)
00474 {
00475 ERRORPRINTF("Invalid page when handling render result");
00476 return;
00477 }
00478
00479 if (render_res != 0)
00480 {
00481
00482
00483 post_prerender_hyperlinks_task(page);
00484 }
00485 }
00486 break;
00487 case TASK_RENDER_OOM:
00488 {
00489
00490 }
00491 break;
00492 case TASK_RENDER_INVALID_PAGE:
00493 {
00494
00495 }
00496 break;
00497 default:
00498 break;
00499 }
00500
00501 if (render_res != 0)
00502 {
00503
00504 doc_controller->sig_page_ready.broadcast(render_res, stat);
00505 }
00506 }
00507
00508 PDFRenderTask* PDFRenderer::gen_render_task(int page_num,
00509 const PDFRenderAttributes &page_attr,
00510 PluginRenderResultImpl *render_res,
00511 int ref_id)
00512 {
00513 return (new PDFRenderTask(page_num,
00514 page_attr,
00515 doc_controller,
00516 render_res,
00517 ref_id));
00518 }
00519
00520 PDFRenderTask* PDFRenderer::gen_render_task(PagePtr page,
00521 const PDFRenderAttributes &page_attr,
00522 PluginRenderResultImpl *render_res,
00523 int ref_id)
00524 {
00525 return (new PDFRenderTask(page,
00526 page_attr,
00527 doc_controller,
00528 render_res,
00529 ref_id));
00530 }
00531
00532 PagePtr PDFRenderer::gen_page(int page_num, const PDFRenderAttributes &attr)
00533 {
00534 PagePtr page = new PDFPage(page_num, attr);
00535 page->set_doc_controller(doc_controller);
00536
00537
00538 doc_controller->pages_cache.add_page(page);
00539
00540 return page;
00541 }
00542
00543 PagePtr PDFRenderer::gen_page(int page_num)
00544 {
00545
00546 PagePtr page = new PDFPage(page_num, cur_render_attr);
00547 page->set_doc_controller(doc_controller);
00548
00549
00550 doc_controller->pages_cache.add_page(page);
00551
00552 return page;
00553 }
00554
00555 }
00556