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 "log.h"
00028 #include "utils.h"
00029 #include "font_cache.h"
00030 #include "pango_renderer.h"
00031
00032 #include "text_config.h"
00033 #include "text_view.h"
00034 #include "text_tasks.h"
00035
00036 namespace text
00037 {
00038
00039 TextView::TextView(TextModel *m)
00040 : model(m),
00041 ctrl(0),
00042 font_family(DEFAULT_ASCII_FONT),
00043 font_size(DEFAULT_FONT_SIZE),
00044 display_width(DEFAULT_SURFACE_WIDTH),
00045 display_height(DEFAULT_SURFACE_HEIGHT),
00046 dpi(DEFAULT_DPI),
00047 color_depth(DEFAULT_COLOR_DEPTH),
00048 line_height(0),
00049 lines_per_page(0),
00050 left_margin(DEFAULT_LEFT_MARGIN),
00051 right_margin(DEFAULT_RIGHT_MARGIN),
00052 top_margin(DEFAULT_TOP_MARGIN),
00053 bottom_margin(DEFAULT_BOTTOM_MARGIN),
00054 client_width(display_width - left_margin - right_margin),
00055 client_height(display_height - top_margin - bottom_margin),
00056 pango_context(0),
00057 pango_mutex(0),
00058 font_hash_code(0),
00059 is_repagination_needed(false),
00060 blank_lines(0)
00061 {
00062
00063 const char *enc = model->get_encoding().c_str();
00064 #ifdef WIN32
00065 if (_stricmp(enc, "GB2312") == 0 || _stricmp(enc, "GBK") == 0)
00066 #else
00067 if (strcasecmp(enc, "GB2312") == 0 || strcasecmp(enc, "GBK") == 0)
00068 #endif
00069 {
00070 font_family = DEFAULT_CHINESE_FONT;
00071 }
00072 initialize();
00073 }
00074
00075 TextView::~TextView()
00076 {
00077 deinitialize();
00078 }
00079
00080 void TextView::initialize()
00081 {
00082
00083 pango_mutex = g_mutex_new();
00084
00085
00086 pango_context_init();
00087
00088 calculate_lines_per_page();
00089 }
00090
00091 void TextView::deinitialize()
00092 {
00093
00094 pango_context_final();
00095 g_mutex_free(pango_mutex);
00096 }
00097
00098 void TextView::pango_context_init()
00099 {
00100
00101 PangoFT2FontMap *font_map = PANGO_FT2_FONT_MAP(pango_ft2_font_map_new());
00102
00103
00104 pango_ft2_font_map_set_resolution(font_map, dpi, dpi);
00105
00106
00107 pango_context = pango_ft2_font_map_create_context(font_map);
00108
00109
00110 PangoFontDescription* font_desc = pango_font_description_new();
00111 pango_font_description_set_family(font_desc, font_family.c_str());
00112 pango_font_description_set_size(font_desc, font_size * PANGO_SCALE);
00113 pango_context_set_font_description(pango_context, font_desc);
00114
00115 char *desc_str = pango_font_description_to_string(font_desc);
00116 font_hash_code = make_hash_code(desc_str,
00117 static_cast<unsigned int>(strlen(desc_str)));
00118 g_free(desc_str);
00119
00120
00121
00122 pango_font_description_free(font_desc);
00123 }
00124
00125 void TextView::pango_context_final()
00126 {
00127
00128 PangoFT2FontMap* font_map = PANGO_FT2_FONT_MAP(pango_context_get_font_map(pango_context));
00129 pango_ft2_font_map_substitute_changed(font_map);
00130
00131
00132 if (pango_context != NULL)
00133 {
00134 g_object_unref(pango_context);
00135 pango_context = NULL;
00136 }
00137 }
00138
00139 bool TextView::paginate(const Position& start_pos)
00140 {
00141
00142 Position in_pos(0, 0);
00143 Position out_pos;
00144 bool forward = true;
00145
00146 size_t page_count = pages.size();
00147 if (page_count == 0)
00148 {
00149 in_pos = start_pos;
00150 }
00151 else if (pages.back().end != Position(0, 0))
00152 {
00153
00154 in_pos = pages.back().end;
00155 }
00156 else if (pages.front().start != Position(0, 0))
00157 {
00158
00159 in_pos = pages.front().start;
00160 forward = false;
00161 }
00162 else
00163 {
00164
00165 return true;
00166 }
00167
00168 if (forward)
00169 {
00170 calculate_next_page_pos(in_pos, out_pos);
00171 pages.push_back(PageInfo(in_pos, out_pos));
00172 }
00173 else
00174 {
00175 calculate_prev_page_pos(in_pos, out_pos);
00176 pages.push_front(PageInfo(out_pos, in_pos));
00177 }
00178 return false;
00179 }
00180
00181 bool TextView::get_anchor_by_page(unsigned int page_index, Position& pos)
00182 {
00183 if (pages.size() == 0)
00184 {
00185
00186 if (page_index == 0)
00187 {
00188
00189 pos = Position(0, 0);
00190 return true;
00191 }
00192 else
00193 {
00194 return false;
00195 }
00196 }
00197 else
00198 {
00199
00200 if (page_index >= pages.size())
00201 {
00202 return false;
00203 }
00204 else
00205 {
00206 pos = pages[page_index].start;
00207 return true;
00208 }
00209 }
00210 }
00211
00212 PangoLayout* TextView::create_layout(const char *str, int len)
00213 {
00214 PangoLayout *layout = pango_layout_new(pango_context);
00215 assert(layout != NULL);
00216
00217 pango_layout_set_width(layout, client_width * PANGO_SCALE);
00218 pango_layout_set_spacing(layout, DEFAULT_LINE_SPACING * PANGO_SCALE);
00219 pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
00220 pango_layout_set_justify(layout, TRUE);
00221 pango_layout_set_text(layout, str, len);
00222 pango_layout_set_single_paragraph_mode(layout, TRUE);
00223 return layout;
00224 }
00225
00226 void TextView::calculate_lines_per_page()
00227 {
00228
00229 const std::string *str = model->get_paragraph(0);
00230 unsigned int sample_len = MIN(32, static_cast<int>(str->size()));
00231 PangoLayout *layout = create_layout(str->c_str(), sample_len);
00232
00233 PangoRectangle rect;
00234 PangoLayoutIter *iter = pango_layout_get_iter(layout);
00235 PangoLayoutLine *pango_line = pango_layout_iter_get_line_readonly(iter);
00236 pango_layout_line_get_pixel_extents(pango_line, NULL, &rect);
00237 line_height = rect.height;
00238 lines_per_page = (client_height + DEFAULT_LINE_SPACING) / (line_height + DEFAULT_LINE_SPACING);
00239 pango_layout_iter_free(iter);
00240
00241
00242 g_object_unref(layout);
00243 }
00244
00245 bool TextView::calculate_prev_page_pos(const Position& in_pos, Position& out_pos)
00246 {
00247
00248 if (in_pos == Position(0, 0))
00249 {
00250 return false;
00251 }
00252
00253
00254 size_t page_count = pages.size();
00255 for (unsigned int i=0; i<page_count; i++)
00256 {
00257 if (pages[i].end == in_pos)
00258 {
00259 out_pos = pages[i].start;
00260 return true;
00261 }
00262 }
00263
00264 g_mutex_lock(pango_mutex);
00265 unsigned int start_paragraph = in_pos.paragraph;
00266 unsigned int start_offset = in_pos.offset;
00267 PangoLayout *layout = NULL;
00268 if (start_offset == 0)
00269 {
00270 start_paragraph--;
00271 }
00272
00273 unsigned int total_lines = 0;
00274 while (total_lines < lines_per_page)
00275 {
00276 if (static_cast<int>(start_paragraph) < 0)
00277 {
00278 if (in_pos > Position(0, 0))
00279 {
00280 blank_lines = lines_per_page - total_lines;
00281 }
00282 break;
00283 }
00284
00285 if (layout != NULL)
00286 {
00287 g_object_unref(layout);
00288 layout = NULL;
00289 }
00290 const std::string *str = model->get_paragraph(start_paragraph);
00291 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00292
00293 int line_count = pango_layout_get_line_count(layout);
00294 if (start_offset != 0)
00295 {
00296
00297 int line_offset, x_pos;
00298 pango_layout_index_to_line_x(layout, start_offset, FALSE, &line_offset, &x_pos);
00299 line_count = line_offset;
00300 }
00301
00302 if (total_lines + line_count < lines_per_page)
00303 {
00304
00305 total_lines += line_count;
00306 start_paragraph--;
00307 start_offset = 0;
00308 }
00309 else if (total_lines + line_count == lines_per_page)
00310 {
00311 out_pos.paragraph = start_paragraph;
00312 out_pos.offset = 0;
00313 break;
00314 }
00315 else
00316 {
00317
00318 PangoLayoutIter *iter = pango_layout_get_iter(layout);
00319 unsigned int line_index = line_count - (lines_per_page - total_lines);
00320 for (unsigned int i=0; i<line_index; i++)
00321 {
00322 pango_layout_iter_next_line(iter);
00323 }
00324
00325 out_pos.paragraph = start_paragraph;
00326 out_pos.offset = pango_layout_iter_get_index(iter);
00327 pango_layout_iter_free(iter);
00328 break;
00329 }
00330 }
00331
00332 if (layout != NULL)
00333 {
00334 g_object_unref(layout);
00335 layout = NULL;
00336 }
00337 g_mutex_unlock(pango_mutex);
00338 return (static_cast<int>(start_paragraph) >= 0);
00339 }
00340
00341 bool TextView::calculate_next_page_pos(const Position& in_pos, Position& out_pos)
00342 {
00343
00344 size_t page_count = pages.size();
00345 for (unsigned int i=0; i<page_count; i++)
00346 {
00347 if (pages[i].start == in_pos)
00348 {
00349 out_pos = pages[i].end;
00350 return out_pos != Position(0, 0);
00351 }
00352 }
00353
00354 unsigned int start_paragraph = in_pos.paragraph;
00355 unsigned int start_offset = in_pos.offset;
00356 unsigned int total_lines = 0;
00357
00358 g_mutex_lock(pango_mutex);
00359 PangoLayout *layout = NULL;
00360 while (total_lines < lines_per_page)
00361 {
00362 if (start_paragraph >= model->get_paragraph_count())
00363 {
00364 break;
00365 }
00366
00367 if (layout != NULL)
00368 {
00369 g_object_unref(layout);
00370 layout = NULL;
00371 }
00372 const std::string *str = model->get_paragraph(start_paragraph);
00373 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00374
00375 int line_count = pango_layout_get_line_count(layout);
00376 int line_offset = 0;
00377 if (start_offset != 0)
00378 {
00379
00380 int x_pos;
00381 pango_layout_index_to_line_x(layout, start_offset, FALSE, &line_offset, &x_pos);
00382 line_count -= line_offset;
00383 }
00384
00385 if (total_lines + line_count < lines_per_page)
00386 {
00387
00388 total_lines += line_count;
00389 start_paragraph++;
00390 start_offset = 0;
00391 }
00392 else if (total_lines + line_count == lines_per_page)
00393 {
00394 if (++start_paragraph < model->get_paragraph_count())
00395 {
00396 out_pos.paragraph = start_paragraph;
00397 out_pos.offset = 0;
00398 }
00399 break;
00400 }
00401 else
00402 {
00403
00404 PangoLayoutIter *iter = pango_layout_get_iter(layout);
00405 for (unsigned int i=0; i<lines_per_page-total_lines+line_offset; i++)
00406 {
00407 pango_layout_iter_next_line(iter);
00408 }
00409
00410 out_pos.offset = pango_layout_iter_get_index(iter);
00411 out_pos.paragraph = start_paragraph;
00412 pango_layout_iter_free(iter);
00413 break;
00414 }
00415 }
00416
00417 if (layout != NULL)
00418 {
00419 g_object_unref(layout);
00420 layout = NULL;
00421 }
00422 g_mutex_unlock(pango_mutex);
00423 return (start_paragraph < model->get_paragraph_count());
00424 }
00425
00426 void TextView::check_page_table(const Position& rendering_pos)
00427 {
00428 size_t page_count = pages.size();
00429 for (unsigned int i=0; i<page_count; i++)
00430 {
00431 if (pages[i].start == rendering_pos)
00432 {
00433 return;
00434 }
00435 }
00436
00437
00438
00439 is_repagination_needed = true;
00440 }
00441
00442 unsigned int TextView::get_page_index_by_anchor(const Position& anchor)
00443 {
00444
00445 size_t page_count = pages.size();
00446
00447
00448 if (page_count == 0 || pages[page_count-1].end != Position(0, 0))
00449 {
00450 return 0;
00451 }
00452
00453 for (unsigned int i=0; i<page_count; i++)
00454 {
00455 if (pages[i].end > anchor && pages[i].start <= anchor)
00456 {
00457 return i;
00458 }
00459 }
00460
00461 return static_cast<unsigned int>(page_count-1);
00462 }
00463
00464 Position TextView::get_page_anchor_by_anchor(const Position& anchor)
00465 {
00466
00467 size_t page_count = pages.size();
00468 for (unsigned int i=0; i<page_count; i++)
00469 {
00470 if (pages[i].end > anchor && pages[i].start <= anchor)
00471 {
00472 return pages[i].start;
00473 }
00474 }
00475
00476 if (page_count>0 && pages[page_count-1].end == Position(0, 0))
00477 {
00478 return pages[page_count-1].start;
00479 }
00480
00481 return Position(anchor.paragraph, 0);
00482 }
00483
00484 unsigned int TextView::get_current_page_index()
00485 {
00486 return get_page_index_by_anchor(rendering_pos);
00487 }
00488
00489 Position TextView::render(unsigned char *bmp, const Position& start_pos)
00490 {
00491 if (is_repagination_needed)
00492 {
00493 pages.clear();
00494 blank_lines = 0;
00495 ctrl->paginate(start_pos, true );
00496 is_repagination_needed = false;
00497 }
00498
00499 g_mutex_lock(pango_mutex);
00500 unsigned int start_paragraph = start_pos.paragraph;
00501 unsigned int start_offset = start_pos.offset;
00502 PangoLayout *layout = NULL;
00503
00504 rendering_pos = start_pos;
00505
00506 unsigned int total_lines = 0;
00507 if (start_pos == Position(0, 0))
00508 {
00509 total_lines = blank_lines;
00510 }
00511 int y_offset = (line_height + DEFAULT_LINE_SPACING)*total_lines*PANGO_SCALE;
00512
00513
00514
00515 if (start_offset != 0)
00516 {
00517 if (layout != NULL)
00518 {
00519 g_object_unref(layout);
00520 layout = NULL;
00521 }
00522 const std::string *str = model->get_paragraph(start_paragraph);
00523 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00524
00525 PangoLayoutIter *iter = pango_layout_get_iter(layout);
00526
00527 int line_offset, x_pos;
00528 pango_layout_index_to_line_x(layout, start_offset, FALSE, &line_offset, &x_pos);
00529 y_offset = (line_height + DEFAULT_LINE_SPACING)*line_offset*PANGO_SCALE;
00530
00531 int baseline = 0;
00532 for (int i=0; i<line_offset; i++)
00533 {
00534 pango_layout_iter_next_line(iter);
00535 }
00536
00537 do
00538 {
00539 baseline = pango_layout_iter_get_baseline(iter) - y_offset;
00540 PangoLayoutLine *pango_line = pango_layout_iter_get_line_readonly(iter);
00541 render_single_line(bmp,
00542 pango_line,
00543 font_hash_code,
00544 left_margin * PANGO_SCALE,
00545 baseline+top_margin*PANGO_SCALE,
00546 (display_width+3)/4*4);
00547 if (++total_lines == lines_per_page)
00548 {
00549
00550 int index, trailing;
00551 pango_layout_line_x_to_index(pango_line, client_width - 1, &index, &trailing);
00552 start_offset = index;
00553 pango_layout_iter_free(iter);
00554 goto RenderEnd;
00555 }
00556 } while (pango_layout_iter_next_line(iter));
00557
00558
00559 pango_layout_iter_free(iter);
00560
00561 start_paragraph++;
00562 y_offset = (line_height + DEFAULT_LINE_SPACING)*total_lines*PANGO_SCALE;
00563 }
00564
00565
00566 while (start_paragraph < model->get_paragraph_count())
00567 {
00568
00569 if (layout != NULL)
00570 {
00571 g_object_unref(layout);
00572 layout = NULL;
00573 }
00574 const std::string *str = model->get_paragraph(start_paragraph);
00575 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00576
00577 PangoLayoutIter *iter = pango_layout_get_iter(layout);
00578 int baseline = 0;
00579 do
00580 {
00581 baseline = pango_layout_iter_get_baseline(iter) + y_offset;
00582 PangoLayoutLine *pango_line = pango_layout_iter_get_line_readonly(iter);
00583 render_single_line(bmp,
00584 pango_line,
00585 font_hash_code,
00586 left_margin * PANGO_SCALE,
00587 baseline+top_margin*PANGO_SCALE,
00588 (display_width+3)/4*4);
00589 if (++total_lines == lines_per_page)
00590 {
00591 int index, trailing;
00592 pango_layout_line_x_to_index(pango_line, client_width - 1, &index, &trailing);
00593 start_offset = index;
00594 pango_layout_iter_free(iter);
00595 goto RenderEnd;
00596 }
00597 } while (pango_layout_iter_next_line(iter));
00598 pango_layout_iter_free(iter);
00599
00600 start_paragraph++;
00601 y_offset = (line_height + DEFAULT_LINE_SPACING)*total_lines*PANGO_SCALE;
00602 }
00603
00604 RenderEnd:
00605
00606 if (layout != NULL)
00607 {
00608 g_object_unref(layout);
00609 layout = NULL;
00610 }
00611 g_mutex_unlock(pango_mutex);
00612
00613 return Position(start_paragraph, start_offset);
00614 }
00615
00616 bool TextView::set_font_size(int font_size)
00617 {
00618 if (this->font_size == font_size)
00619 {
00620 return true;
00621 }
00622
00623 this->font_size = font_size;
00624
00625 g_mutex_lock(pango_mutex);
00626
00627
00628 PangoFT2FontMap* font_map = PANGO_FT2_FONT_MAP(pango_context_get_font_map(pango_context));
00629 pango_ft2_font_map_substitute_changed(font_map);
00630
00631
00632 PangoFontDescription* font_desc = pango_font_description_new();
00633 pango_font_description_set_family(font_desc, font_family.c_str());
00634 pango_font_description_set_size(font_desc, font_size * PANGO_SCALE);
00635 pango_context_set_font_description(pango_context, font_desc);
00636
00637 char *desc_str = pango_font_description_to_string(font_desc);
00638 font_hash_code = make_hash_code(desc_str,
00639 static_cast<unsigned int>(strlen(desc_str)));
00640 g_free(desc_str);
00641
00642
00643
00644 pango_font_description_free(font_desc);
00645 calculate_lines_per_page();
00646
00647
00648 is_repagination_needed = true;
00649
00650
00651 FontCache& font_cache = FontCache::instance();
00652 font_cache.clear();
00653
00654 g_mutex_unlock(pango_mutex);
00655 return true;
00656 }
00657
00658 void TextView::set_display_size(unsigned int width, unsigned int height)
00659 {
00660 LOGPRINTF("\n\nwidth=%d, height=%d\n\n", width, height);
00661 if (width == display_width && height == display_height)
00662 {
00663 return;
00664 }
00665
00666 g_mutex_lock(pango_mutex);
00667 if (height != display_height)
00668 {
00669
00670
00671 display_height = height;
00672 client_height = display_height - top_margin - bottom_margin;
00673 calculate_lines_per_page();
00674 }
00675
00676 if (width != display_width)
00677 {
00678 display_width = width;
00679 client_width = display_width - left_margin - right_margin;
00680 }
00681
00682
00683 is_repagination_needed = true;
00684 g_mutex_unlock(pango_mutex);
00685 }
00686
00687 bool TextView::map_doc_pos_to_view_pos(const Position& page_anchor,
00688 const Position& doc_pos,
00689 ViewPosition& view_pos,
00690 bool trailing)
00691 {
00692 if (doc_pos < page_anchor)
00693 {
00694 return false;
00695 }
00696
00697 unsigned int line_height_with_spacing = line_height + DEFAULT_LINE_SPACING;
00698
00699
00700 const std::string *str = model->get_paragraph(doc_pos.paragraph);
00701 PangoLayout *layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00702
00703 int line_offset_pos, x_offset_pos;
00704 pango_layout_index_to_line_x(layout, doc_pos.offset, trailing, &line_offset_pos, &x_offset_pos);
00705
00706 unsigned int total_lines = 0;
00707 unsigned int start_paragraph = page_anchor.paragraph;
00708 unsigned int start_offset = page_anchor.offset;
00709 if (start_paragraph == 0 && start_offset == 0)
00710 {
00711 total_lines += blank_lines;
00712 }
00713
00714 if (start_offset != 0)
00715 {
00716
00717 if (layout != NULL)
00718 {
00719 g_object_unref(layout);
00720 layout = NULL;
00721 }
00722 const std::string *str = model->get_paragraph(start_paragraph);
00723 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00724
00725 int line_offset_start, x_pos;
00726 pango_layout_index_to_line_x(layout, start_offset, FALSE, &line_offset_start, &x_pos);
00727
00728 if (doc_pos.paragraph == start_paragraph)
00729 {
00730 total_lines = line_offset_pos - line_offset_start;
00731 goto MapEnd;
00732 }
00733 else
00734 {
00735 total_lines = pango_layout_get_line_count(layout) - line_offset_start;
00736 start_paragraph++;
00737 }
00738 }
00739
00740 for (; start_paragraph != doc_pos.paragraph; start_paragraph++)
00741 {
00742 if (layout != NULL)
00743 {
00744 g_object_unref(layout);
00745 layout = NULL;
00746 }
00747 const std::string *str = model->get_paragraph(start_paragraph);
00748 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00749
00750 total_lines += pango_layout_get_line_count(layout);
00751 }
00752
00753 total_lines += line_offset_pos;
00754
00755 MapEnd:
00756 if (layout != NULL)
00757 {
00758 g_object_unref(layout);
00759 layout = NULL;
00760 }
00761 if (total_lines < lines_per_page)
00762 {
00763 view_pos.x = PANGO_PIXELS(x_offset_pos) + left_margin;
00764 view_pos.y = top_margin + line_height_with_spacing * total_lines;
00765 return true;
00766 }
00767 else
00768 {
00769 return false;
00770 }
00771 }
00772
00773 bool TextView::map_view_pos_to_doc_pos(const Position& page_anchor,
00774 const ViewPosition& view_pos,
00775 Position& doc_pos)
00776 {
00777 int x_offset_pos = view_pos.x - left_margin;
00778 int y_offset_pos = view_pos.y - top_margin;
00779
00780 unsigned int start_paragraph = page_anchor.paragraph;
00781 unsigned int start_offset = page_anchor.offset;
00782 unsigned int line_height_with_spacing = line_height + DEFAULT_LINE_SPACING;
00783
00784 if (start_paragraph == 0 && start_offset == 0)
00785 {
00786 y_offset_pos -= blank_lines * line_height_with_spacing;
00787 }
00788
00789 PangoLayout *layout = NULL;
00790 bool found = false;
00791
00792 if (start_offset != 0)
00793 {
00794 const std::string *str = model->get_paragraph(start_paragraph);
00795 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00796
00797 int line_offset_start, x_pos;
00798 pango_layout_index_to_line_x(layout, start_offset, FALSE, &line_offset_start, &x_pos);
00799
00800 int lines_left = pango_layout_get_line_count(layout) - line_offset_start;
00801 if (static_cast<int>(lines_left * line_height_with_spacing) > y_offset_pos)
00802 {
00803
00804 doc_pos.paragraph = start_paragraph;
00805
00806
00807 int bytes_index, trailing;
00808 pango_layout_xy_to_index(layout,
00809 x_offset_pos * PANGO_SCALE,
00810 (line_offset_start*line_height_with_spacing+y_offset_pos) * PANGO_SCALE,
00811 &bytes_index, &trailing);
00812 doc_pos.offset = bytes_index;
00813 found = true;
00814 goto MapEnd;
00815 }
00816 else
00817 {
00818 y_offset_pos -= lines_left * line_height_with_spacing;
00819 start_paragraph++;
00820 }
00821 }
00822
00823 for (; start_paragraph < model->get_paragraph_count(); start_paragraph++)
00824 {
00825 if (layout != NULL)
00826 {
00827 g_object_unref(layout);
00828 layout = NULL;
00829 }
00830 const std::string *str = model->get_paragraph(start_paragraph);
00831 layout = create_layout(str->c_str(), static_cast<int>(str->size()));
00832
00833 int line_count = pango_layout_get_line_count(layout);
00834 if (static_cast<int>(line_count * line_height_with_spacing) > y_offset_pos)
00835 {
00836 break;
00837 }
00838 else
00839 {
00840 y_offset_pos -= line_count * line_height_with_spacing;
00841 }
00842 }
00843
00844 if (start_paragraph == model->get_paragraph_count())
00845 {
00846 goto MapEnd;
00847 }
00848
00849 int bytes_index, trailing;
00850 pango_layout_xy_to_index(layout, x_offset_pos * PANGO_SCALE, y_offset_pos * PANGO_SCALE, &bytes_index, &trailing);
00851 doc_pos.paragraph = start_paragraph;
00852 doc_pos.offset = bytes_index;
00853 found = true;
00854
00855 MapEnd:
00856 if (layout)
00857 {
00858 g_object_unref(layout);
00859 }
00860 return found;
00861 }
00862
00863 bool TextView::get_bounding_rectangles(const Position& page_anchor,
00864 std::vector<Rect>& bounding_rect,
00865 const Range& range)
00866 {
00867
00868
00869 bool span_pages = false;
00870 ViewPosition view_pos_start, view_pos_end;
00871
00872 if (!map_doc_pos_to_view_pos(page_anchor, range.start, view_pos_start, false))
00873 {
00874
00875
00876 return false;
00877 }
00878
00879 if (!map_doc_pos_to_view_pos(page_anchor, range.end, view_pos_end, true))
00880 {
00881
00882
00883 span_pages = true;
00884 }
00885
00886 unsigned int line_height_with_spacing = line_height + DEFAULT_LINE_SPACING;
00887
00888
00889 if (view_pos_start.y == view_pos_end.y)
00890 {
00891
00892 bounding_rect.push_back(Rect(view_pos_start.x,
00893 view_pos_start.y + DEFAULT_LINE_SPACING,
00894 view_pos_end.x - view_pos_start.x,
00895 line_height));
00896 }
00897 else
00898 {
00899
00900 bounding_rect.push_back(Rect(view_pos_start.x,
00901 view_pos_start.y + DEFAULT_LINE_SPACING,
00902 display_width - view_pos_start.x - right_margin,
00903 line_height));
00904
00905 for (unsigned int y_offset = view_pos_start.y+line_height_with_spacing;
00906 static_cast<int>(y_offset) < view_pos_end.y &&
00907 y_offset < top_margin + line_height_with_spacing * lines_per_page;
00908 y_offset += line_height_with_spacing)
00909 {
00910 bounding_rect.push_back(Rect(left_margin,
00911 y_offset + DEFAULT_LINE_SPACING,
00912 client_width,
00913 line_height));
00914 }
00915
00916 if (!span_pages)
00917 {
00918 bounding_rect.push_back(Rect(left_margin,
00919 view_pos_end.y + DEFAULT_LINE_SPACING,
00920 view_pos_end.x - left_margin,
00921 line_height));
00922 }
00923 }
00924
00925 return true;
00926 }
00927
00928 }