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
00028
00029 #include <gnome.h>
00030 #include <gdk/gdk.h>
00031 #include <string.h>
00032 #include "cr-lay-eng.h"
00033 #include "cr-sel-eng.h"
00034
00035 #define PRIVATE(a_this) ((a_this)->priv)
00036
00037
00038
00039
00040
00041
00042
00043
00044 struct _CRLayEngPriv
00045 {
00046 gboolean update_parent_box_size ;
00047 CRCascade *cascade ;
00048 CRSelEng *sel_eng ;
00049 GtkLayout *layout ;
00050 gulong xdpi ;
00051 gulong ydpi ;
00052 gulong rightmost_x ;
00053 } ;
00054
00055
00056 enum CRDirection
00057 {
00058 DIR_UNKNOWN = 0,
00059 DIR_VERTICAL,
00060 DIR_HORIZONTAL
00061 } ;
00062
00063 static gboolean gv_layeng_initialized = FALSE ;
00064
00065 static void
00066 init_anonymous_text_box (CRBox *a_box) ;
00067
00068 static enum CRStatus
00069 style_specified_2_computed_values (CRLayEng *a_this,
00070 CRStyle *a_style,
00071 CRBox *a_parent_box) ;
00072
00073 static CRBox *
00074 create_box_tree_real (CRLayEng * a_this,
00075 xmlNode *a_root_node,
00076 CRBox *a_parent_box) ;
00077
00078 static glong
00079 get_box_bottommost_y (CRBox *a_this) ;
00080
00081 static glong
00082 get_box_rightmost_x (CRBox *a_this) ;
00083
00084 static enum CRStatus
00085 compute_and_set_box_dimensions (CRLayEng *a_this,
00086 CRBox *a_cur_box) ;
00087
00088 static enum CRStatus
00089 layout_inline_box (CRLayEng *a_this,
00090 CRBox *a_cur_box) ;
00091
00092 static enum CRStatus
00093 layout_block_box (CRLayEng *a_this,
00094 CRBox *a_cur_box) ;
00095
00096 static enum CRStatus
00097 layout_box_in_normal_flow (CRLayEng *a_this,
00098 CRBox *a_cur_box) ;
00099
00100 static enum CRStatus
00101 layout_box (CRLayEng *a_this, CRBox *a_cur_box) ;
00102
00103 static enum CRStatus
00104 compute_text_box_inner_edge_size (CRLayEng *a_this,
00105 CRBox *a_box) ;
00106
00107 static enum CRStatus
00108 adjust_parent_inner_edge_size (CRLayEng *a_this,
00109 CRBox *a_cur_box) ;
00110
00111 static enum CRStatus
00112 normalize_num (CRLayEng *a_this,
00113 CRNum *a_dest_num,
00114 CRNum *a_src_num,
00115 enum CRDirection a_dir) ;
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 static void
00129 init_anonymous_text_box (CRBox *a_box)
00130 {
00131 glong i = 0 ;
00132
00133 g_return_if_fail (a_box && a_box->style) ;
00134
00135 for (i = 0 ; i< NB_NUM_PROPS ; i++)
00136 {
00137 switch (i)
00138 {
00139 case NUM_PROP_PADDING_TOP:
00140 case NUM_PROP_PADDING_RIGHT:
00141 case NUM_PROP_PADDING_BOTTOM:
00142 case NUM_PROP_PADDING_LEFT:
00143 case NUM_PROP_BORDER_TOP:
00144 case NUM_PROP_BORDER_RIGHT:
00145 case NUM_PROP_BORDER_BOTTOM:
00146 case NUM_PROP_BORDER_LEFT:
00147 case NUM_PROP_MARGIN_TOP:
00148 case NUM_PROP_MARGIN_RIGHT:
00149 case NUM_PROP_MARGIN_BOTTOM:
00150 case NUM_PROP_MARGIN_LEFT:
00151 cr_num_set (&a_box->style->num_props[i].sv,
00152 0, NUM_LENGTH_PX) ;
00153 break ;
00154
00155 default:
00156 break ;
00157 }
00158
00159 }
00160
00161 for (i = 0 ; i< NB_BORDER_STYLE_PROPS ; i++)
00162 {
00163 a_box->style->border_style_props[i] = BORDER_STYLE_NONE ;
00164 }
00165
00166 a_box->style->float_type = FLOAT_NONE ;
00167 }
00168
00169
00170 static enum CRStatus
00171 normalize_num (CRLayEng *a_this,
00172 CRNum *a_dest_num,
00173 CRNum *a_src_num,
00174 enum CRDirection a_dir)
00175 {
00176 g_return_val_if_fail (a_this && a_dest_num
00177 && a_src_num,
00178 CR_BAD_PARAM_ERROR) ;
00179
00180 switch (a_src_num->type)
00181 {
00182 case NUM_LENGTH_PX:
00183 cr_num_copy (a_dest_num, a_src_num) ;
00184
00185 break ;
00186
00187 case NUM_LENGTH_EM:
00188 case NUM_LENGTH_EX:
00189 break ;
00190
00191 case NUM_LENGTH_IN:
00192 if (a_dir == DIR_HORIZONTAL)
00193 {
00194 a_dest_num->val = a_src_num->val
00195 * PRIVATE (a_this)->xdpi ;
00196 }
00197 else if (a_dir == DIR_VERTICAL)
00198 {
00199 a_dest_num->val = a_src_num->val
00200 * PRIVATE (a_this)->ydpi ;
00201 }
00202 else
00203 {
00204 cr_utils_trace_info ("Bad direction given") ;
00205 return CR_BAD_PARAM_ERROR ;
00206 }
00207 a_dest_num->type = NUM_LENGTH_PX ;
00208 break ;
00209
00210 case NUM_LENGTH_CM:
00211
00212 if (a_dir == DIR_HORIZONTAL)
00213 {
00214 a_dest_num->val = a_src_num->val / 2.54 *
00215 PRIVATE (a_this)->xdpi ;
00216 }
00217 else if (a_dir == DIR_VERTICAL)
00218 {
00219 a_dest_num->val = a_src_num->val / 2.54 *
00220 PRIVATE (a_this)->ydpi ;
00221 }
00222 else
00223 {
00224 cr_utils_trace_info ("Bad direction given") ;
00225 return CR_BAD_PARAM_ERROR ;
00226 }
00227
00228 a_dest_num->type = NUM_LENGTH_PX ;
00229 break ;
00230
00231 case NUM_LENGTH_MM:
00232
00233 if (a_dir == DIR_HORIZONTAL)
00234 {
00235 a_dest_num->val = a_src_num->val / 25.4 *
00236 PRIVATE (a_this)->xdpi ;
00237 }
00238 else if (a_dir == DIR_VERTICAL)
00239 {
00240 a_dest_num->val = a_src_num->val / 25.4 *
00241 PRIVATE (a_this)->ydpi ;
00242 }
00243 else
00244 {
00245 cr_utils_trace_info ("Bad direction given") ;
00246 return CR_BAD_PARAM_ERROR ;
00247 }
00248 a_dest_num->type = NUM_LENGTH_PX ;
00249 break ;
00250
00251 case NUM_LENGTH_PT:
00252
00253 if (a_dir == DIR_HORIZONTAL)
00254 {
00255 a_dest_num->val = a_src_num->val *
00256 PRIVATE (a_this)->xdpi / 72 ;
00257 }
00258 else if (a_dir == DIR_VERTICAL)
00259 {
00260 a_dest_num->val = a_src_num->val *
00261 PRIVATE (a_this)->ydpi / 72 ;
00262 }
00263 else
00264 {
00265 cr_utils_trace_info ("Bad direction given") ;
00266 return CR_BAD_PARAM_ERROR ;
00267 }
00268
00269 a_dest_num->type = NUM_LENGTH_PX ;
00270 break ;
00271
00272 case NUM_LENGTH_PC:
00273
00274 if (a_dir == DIR_HORIZONTAL)
00275 {
00276 a_dest_num->val = a_src_num->val *
00277 PRIVATE (a_this)->xdpi / 72 * 12 ;
00278 }
00279 else if (a_dir == DIR_VERTICAL)
00280 {
00281 a_dest_num->val = a_src_num->val *
00282 PRIVATE (a_this)->ydpi / 72 * 12 ;
00283 }
00284 else
00285 {
00286 cr_utils_trace_info ("Bad direction given") ;
00287 return CR_BAD_PARAM_ERROR ;
00288 }
00289
00290 a_dest_num->type = NUM_LENGTH_PX ;
00291 break ;
00292
00293 case NUM_ANGLE_DEG:
00294 a_dest_num->val = a_src_num->val ;
00295
00296 break ;
00297 case NUM_ANGLE_RAD:
00298 a_dest_num->val = a_src_num->val * 180 / 3.1415 ;
00299 a_dest_num->type = NUM_ANGLE_DEG ;
00300 break ;
00301
00302 case NUM_ANGLE_GRAD:
00303 a_dest_num->val = a_src_num->val * 90 / 100 ;
00304 a_dest_num->type = NUM_ANGLE_DEG ;
00305 break ;
00306
00307 case NUM_TIME_MS:
00308 a_dest_num->val = a_src_num->val ;
00309
00310 break ;
00311
00312 case NUM_TIME_S:
00313 a_dest_num->val = a_src_num->val * 1000 ;
00314 a_dest_num->type = NUM_TIME_MS ;
00315 break ;
00316
00317 case NUM_FREQ_HZ:
00318 a_dest_num->val = a_src_num->val ;
00319 break ;
00320
00321 case NUM_FREQ_KHZ:
00322 a_dest_num->val = a_src_num->val * 1000 ;
00323 a_dest_num->type = NUM_FREQ_HZ ;
00324 break ;
00325
00326 case NUM_PERCENTAGE:
00327 cr_utils_trace_info ("a PERCENTAGE cannot be normalized") ;
00328 return CR_BAD_PARAM_ERROR ;
00329
00330 default:
00331
00332 cr_num_copy (a_dest_num, a_src_num) ;
00333 break ;
00334 }
00335
00336 return CR_OK ;
00337 }
00338
00339 static enum CRStatus
00340 style_specified_2_computed_values (CRLayEng *a_this,
00341 CRStyle *a_style,
00342 CRBox *a_parent_box)
00343 {
00344 glong i = 0 ;
00345 CRBoxEdge *parent_inner_edge = NULL;
00346
00347 g_return_val_if_fail (a_style && a_this,
00348 CR_BAD_PARAM_ERROR) ;
00349
00350
00351
00352
00353
00354 for (i = 0 ; i < NB_NUM_PROPS ; i++)
00355 {
00356 switch (i)
00357 {
00358 case NUM_PROP_TOP:
00359 case NUM_PROP_BOTTOM:
00360 case NUM_PROP_PADDING_TOP:
00361 case NUM_PROP_PADDING_BOTTOM:
00362 case NUM_PROP_BORDER_TOP:
00363 case NUM_PROP_BORDER_BOTTOM:
00364 case NUM_PROP_MARGIN_TOP:
00365 case NUM_PROP_MARGIN_BOTTOM:
00366 if (a_style->num_props[i].sv.type == NUM_PERCENTAGE)
00367 {
00368
00369
00370
00371
00372 if (a_parent_box)
00373 {
00374 parent_inner_edge =
00375 &a_parent_box->inner_edge ;
00376 }
00377
00378 g_return_val_if_fail (parent_inner_edge,
00379 CR_BAD_PARAM_ERROR) ;
00380
00381 a_style->num_props[i].cv.val =
00382 parent_inner_edge->height *
00383 a_style->num_props[i].sv.val / 100 ;
00384 }
00385 else
00386 {
00387 normalize_num (a_this,
00388 &a_style->num_props[i].cv,
00389 &a_style->num_props[i].sv,
00390 DIR_VERTICAL) ;
00391 }
00392 break ;
00393
00394 case NUM_PROP_RIGHT:
00395 case NUM_PROP_LEFT:
00396 case NUM_PROP_PADDING_LEFT:
00397 case NUM_PROP_PADDING_RIGHT:
00398 case NUM_PROP_BORDER_LEFT:
00399 case NUM_PROP_BORDER_RIGHT:
00400 case NUM_PROP_MARGIN_LEFT:
00401 case NUM_PROP_MARGIN_RIGHT:
00402 if (a_style->num_props[i].sv.type == NUM_PERCENTAGE)
00403 {
00404
00405
00406
00407
00408 if (a_parent_box)
00409 {
00410 parent_inner_edge =
00411 &a_parent_box->inner_edge ;
00412 }
00413
00414 g_return_val_if_fail (parent_inner_edge,
00415 CR_BAD_PARAM_ERROR) ;
00416
00417 a_style->num_props[i].cv.val =
00418 a_style->parent_style->
00419 num_props[NUM_PROP_WIDTH].cv.val *
00420 a_style->num_props[i].sv.val / 100 ;
00421 }
00422 else
00423 {
00424 normalize_num (a_this,
00425 &a_style->num_props[i].cv,
00426 &a_style->num_props[i].sv,
00427 DIR_HORIZONTAL) ;
00428 }
00429 break ;
00430
00431 case NUM_PROP_WIDTH:
00432 if (a_style->num_props[i].sv.type == NUM_PERCENTAGE)
00433 {
00434
00435
00436
00437
00438 if (a_parent_box)
00439 {
00440 parent_inner_edge =
00441 &a_parent_box->inner_edge ;
00442 }
00443
00444 g_return_val_if_fail (parent_inner_edge,
00445 CR_BAD_PARAM_ERROR) ;
00446
00447 a_style->num_props[i].cv.val =
00448 a_style->parent_style->
00449 num_props[NUM_PROP_WIDTH].cv.val *
00450 a_style->num_props[i].sv.val / 100 ;
00451
00452 a_style->num_props[i].cv.val -=
00453 (a_style->num_props[NUM_PROP_MARGIN_LEFT].cv.val
00454 +a_style->num_props[NUM_PROP_MARGIN_RIGHT].cv.val
00455 +a_style->num_props[NUM_PROP_BORDER_LEFT].cv.val
00456 +a_style->num_props[NUM_PROP_BORDER_RIGHT].cv.val
00457 +a_style->num_props[NUM_PROP_PADDING_LEFT].cv.val
00458 +a_style->num_props[NUM_PROP_PADDING_RIGHT].cv.val);
00459 a_style->num_props[i].cv.type =
00460 NUM_LENGTH_PX ;
00461 }
00462 else
00463 {
00464 normalize_num (a_this,
00465 &a_style->num_props[i].cv,
00466 &a_style->num_props[i].sv,
00467 DIR_HORIZONTAL) ;
00468 }
00469 break ;
00470 default:
00471 normalize_num (a_this,
00472 &a_style->num_props[i].cv,
00473 &a_style->num_props[i].sv,
00474 DIR_UNKNOWN) ;
00475 break ;
00476 }
00477 }
00478
00479 for (i = 0 ; i < NB_RGB_PROPS; i++)
00480 {
00481 cr_rgb_set_from_rgb (&a_style->rgb_props[i].cv,
00482 &a_style->rgb_props[i].sv) ;
00483 }
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 if ((a_style->border_style_props[BORDER_STYLE_PROP_TOP] ==
00498 BORDER_STYLE_NONE)
00499 || (a_style->border_style_props[BORDER_STYLE_PROP_TOP] ==
00500 BORDER_STYLE_HIDDEN))
00501 {
00502 cr_num_set (&a_style->num_props[NUM_PROP_BORDER_TOP].cv,
00503 0, NUM_LENGTH_PX) ;
00504 }
00505
00506 if ((a_style->border_style_props[BORDER_STYLE_PROP_RIGHT] ==
00507 BORDER_STYLE_NONE)
00508 || (a_style->border_style_props[BORDER_STYLE_PROP_RIGHT] ==
00509 BORDER_STYLE_HIDDEN))
00510 {
00511 cr_num_set (&a_style->num_props[NUM_PROP_BORDER_RIGHT].cv,
00512 0, NUM_LENGTH_PX) ;
00513 }
00514
00515 if ((a_style->border_style_props[BORDER_STYLE_PROP_BOTTOM] ==
00516 BORDER_STYLE_NONE)
00517 || (a_style->border_style_props[BORDER_STYLE_PROP_BOTTOM] ==
00518 BORDER_STYLE_HIDDEN))
00519 {
00520 cr_num_set (&a_style->num_props[NUM_PROP_BORDER_BOTTOM].cv,
00521 0, NUM_LENGTH_PX) ;
00522 }
00523
00524 if ((a_style->border_style_props[BORDER_STYLE_PROP_LEFT] ==
00525 BORDER_STYLE_NONE)
00526 || (a_style->border_style_props[BORDER_STYLE_PROP_LEFT] ==
00527 BORDER_STYLE_HIDDEN))
00528 {
00529 cr_num_set (&a_style->num_props[NUM_PROP_BORDER_LEFT].cv,
00530 0, NUM_LENGTH_PX) ;
00531 }
00532
00533
00534 return CR_OK ;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 static CRBox *
00546 create_box_tree_real (CRLayEng * a_this,
00547 xmlNode *a_root_node,
00548 CRBox *a_parent_box)
00549 {
00550 enum CRStatus status = CR_OK ;
00551 xmlNode *cur = NULL ;
00552 CRBox *cur_box = NULL ;
00553 CRBoxData *box_data = NULL ;
00554
00555 g_return_val_if_fail (a_this
00556 && PRIVATE (a_this)
00557 && PRIVATE (a_this)->cascade
00558 && a_root_node, NULL) ;
00559
00560 if (!PRIVATE (a_this)->sel_eng)
00561 {
00562 PRIVATE (a_this)->sel_eng = cr_sel_eng_new () ;
00563 if (!PRIVATE (a_this)->sel_eng)
00564 {
00565 cr_utils_trace_info
00566 ("Could not create selection engine") ;
00567 cr_utils_trace_info
00568 ("System may be out of memory") ;
00569 return NULL ;
00570 }
00571 }
00572
00573 for (cur = a_root_node ; cur ; cur = cur->next)
00574 {
00575 CRStyle *style = NULL, *parent_style = NULL ;
00576
00577 if (cur->type != XML_ELEMENT_NODE
00578 && cur->type != XML_TEXT_NODE)
00579 continue ;
00580
00581
00582 if (cur->parent && a_parent_box && a_parent_box->style)
00583 parent_style = a_parent_box->style ;
00584
00585 if (cur->type == XML_ELEMENT_NODE)
00586 {
00587 status =
00588 cr_sel_eng_get_matched_style
00589 (PRIVATE (a_this)->sel_eng,
00590 PRIVATE (a_this)->cascade,
00591 cur, parent_style, &style) ;
00592
00593 if (status != CR_OK
00594 || (style && style->display == DISPLAY_NONE))
00595 {
00596 continue ;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 cur_box = cr_box_new (style, TRUE) ;
00609 if (!cur_box)
00610 {
00611 cr_utils_trace_info
00612 ("Could not create a box") ;
00613 cr_utils_trace_info
00614 ("The system may be out of memory") ;
00615 return NULL ;
00616 }
00617
00618 if (a_parent_box)
00619 cr_box_append_child (a_parent_box,
00620 cur_box) ;
00621 style = NULL ;
00622
00623
00624
00625
00626
00627 box_data = cr_box_data_new (cur) ;
00628 if (!box_data)
00629 {
00630 cr_utils_trace_info ("Out of memory") ;
00631 goto error ;
00632 }
00633 cur_box->box_data = box_data ;
00634 box_data = NULL ;
00635
00636 if (style)
00637 {
00638 cr_style_destroy (style) ;
00639 style = NULL ;
00640 }
00641 }
00642 else if (cur->type == XML_TEXT_NODE)
00643 {
00644 CRBoxContent *box_content = NULL ;
00645 xmlChar *node_text = NULL ;
00646 CRStyle * style_dup = NULL ;
00647
00648 if (xmlIsBlankNode (cur))
00649 continue ;
00650
00651 node_text = xmlNodeGetContent (cur) ;
00652 if (node_text)
00653 {
00654 box_content =
00655 cr_box_content_new_from_text
00656 (node_text) ;
00657 xmlFree (node_text) ;
00658 node_text = NULL ;
00659 }
00660 if (box_content)
00661 {
00662
00663
00664
00665
00666
00667 style_dup = cr_style_dup (parent_style) ;
00668 if (!style_dup)
00669 {
00670 cr_utils_trace_info
00671 ("cr_style_dup "
00672 "Maybe out of memory") ;
00673 goto error ;
00674 }
00675
00676 cur_box = cr_box_new (style_dup, TRUE) ;
00677 if (!cur_box)
00678 {
00679 cr_utils_trace_info
00680 ("could not create "
00681 "anonymous box") ;
00682 goto error ;
00683 }
00684 cur_box->content = box_content ;
00685 box_content = NULL ;
00686
00687
00688
00689
00690 cur_box->type = BOX_TYPE_INLINE ;
00691 cur_box->style->display = DISPLAY_INLINE ;
00692
00693
00694
00695
00696
00697 box_data = cr_box_data_new (cur) ;
00698 if (!box_data)
00699 {
00700 cr_utils_trace_info
00701 ("Out of memory") ;
00702 goto error ;
00703 }
00704 cur_box->box_data = box_data ;
00705 box_data = NULL ;
00706
00707
00708
00709
00710
00711
00712
00713 init_anonymous_text_box (cur_box) ;
00714
00715
00716
00717
00718 cr_box_append_child (a_parent_box,
00719 cur_box) ;
00720 cur_box = NULL ;
00721
00722
00723 }
00724 }
00725 else
00726 {
00727 cr_utils_trace_info
00728 ("xml node type neither element nor text") ;
00729 cr_utils_trace_info
00730 ("this should not happen. This is a bug") ;
00731 }
00732
00733
00734 if (cur->children)
00735 {
00736 create_box_tree_real
00737 (a_this, cur->children, cur_box) ;
00738 }
00739 }
00740
00741 return cur_box ;
00742
00743 error:
00744 if (cur_box)
00745 {
00746 cr_box_destroy (cur_box) ;
00747 cur_box = NULL ;
00748 }
00749 if (box_data)
00750 {
00751 cr_box_data_destroy (box_data) ;
00752 box_data = NULL ;
00753 }
00754
00755 return NULL ;
00756 }
00757
00758
00759 static glong
00760 get_box_bottommost_y (CRBox *a_this)
00761 {
00762 if (!a_this)
00763 return 0 ;
00764
00765 return (a_this->outer_edge.y
00766 +
00767 a_this->outer_edge.y_offset
00768 +
00769 a_this->outer_edge.height) ;
00770 }
00771
00772
00773
00774
00775
00776
00777
00778
00779 static glong
00780 get_box_rightmost_x (CRBox *a_this)
00781 {
00782 if (!a_this)
00783 return 0 ;
00784
00785 return (a_this->outer_edge.x
00786 +
00787 a_this->outer_edge.x_offset
00788 +
00789 a_this->outer_edge.width) ;
00790 }
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805 static enum CRStatus
00806 compute_text_box_inner_edge_size (CRLayEng *a_this,
00807 CRBox *a_box)
00808 {
00809 enum CRStatus status = CR_OK ;
00810 GtkWidget *label = NULL ;
00811 PangoLayout *pgo_layout = NULL ;
00812 PangoRectangle ink_rect = {0}, logical_rect = {0} ;
00813
00814 g_return_val_if_fail (a_this
00815 && a_box
00816 && a_box->content
00817 && a_box->content->type == TEXT_CONTENT_TYPE,
00818 CR_BAD_PARAM_ERROR) ;
00819
00820 if (a_box->content->u.text == NULL
00821 || strlen (a_box->content->u.text) == 0)
00822 {
00823 a_box->inner_edge.width = 0 ;
00824 a_box->inner_edge.height = 0 ;
00825 return CR_OK ;
00826 }
00827
00828 g_return_val_if_fail (a_box->content->content_cache,
00829 CR_BAD_PARAM_ERROR) ;
00830
00831 label = a_box->content->content_cache ;
00832
00833 if (label->parent == GTK_WIDGET (PRIVATE (a_this)->layout))
00834 gtk_layout_move (PRIVATE (a_this)->layout,
00835 label,
00836 a_box->inner_edge.x,
00837 a_box->inner_edge.y) ;
00838 else
00839 gtk_layout_put (PRIVATE (a_this)->layout,
00840 label,
00841 a_box->inner_edge.x,
00842 a_box->inner_edge.y) ;
00843
00844 gtk_widget_show_all (GTK_WIDGET (PRIVATE (a_this)->layout)) ;
00845
00846 pgo_layout = gtk_label_get_layout (GTK_LABEL (label)) ;
00847
00848 pango_layout_get_pixel_extents (pgo_layout, &ink_rect,
00849 &logical_rect) ;
00850
00851
00852
00853 if (cr_num_is_fixed_length
00854 (&a_box->style->num_props[NUM_PROP_WIDTH].cv))
00855 {
00856 a_box->inner_edge.width =
00857 a_box->style->num_props[NUM_PROP_WIDTH].cv.val ;
00858 }
00859 else
00860 {
00861 a_box->inner_edge.width = logical_rect.width ;
00862 }
00863
00864 a_box->inner_edge.height = logical_rect.height ;
00865
00866 return status ;
00867 }
00868
00869
00870 static enum CRStatus
00871 layout_text_in_box (CRLayEng *a_this, CRBox *a_text_box)
00872 {
00873 enum CRStatus status = CR_OK ;
00874 GtkWidget *label = NULL ;
00875 PangoLayout * pgo_layout = NULL ;
00876 PangoAttrList *pgo_attr_list = NULL ;
00877 glong wrap_width = 0 ;
00878
00879 g_return_val_if_fail (a_this && a_text_box
00880 && a_text_box->content
00881 && (a_text_box->content->type
00882 == TEXT_CONTENT_TYPE)
00883 && a_text_box->content->u.text,
00884 CR_BAD_PARAM_ERROR) ;
00885
00886 g_return_val_if_fail ((a_text_box->parent->inner_edge.max_width
00887 + a_text_box->parent->inner_edge.x)
00888 >= a_text_box->inner_edge.x,
00889 CR_BAD_PARAM_ERROR) ;
00890
00891 if (!a_text_box->content->content_cache)
00892 {
00893 a_text_box->content->content_cache =
00894 gtk_label_new (NULL) ;
00895 g_return_val_if_fail (a_text_box->content->content_cache,
00896 CR_ERROR) ;
00897 }
00898
00899 label = a_text_box->content->content_cache ;
00900 g_return_val_if_fail (GTK_IS_LABEL (label), CR_ERROR) ;
00901
00902 gtk_label_set_text (GTK_LABEL (label),
00903 a_text_box->content->u.text) ;
00904 gtk_misc_set_alignment (GTK_MISC (label),0, 0) ;
00905 gtk_misc_set_padding (GTK_MISC (label), 0, 0) ;
00906 gtk_label_set_use_markup (GTK_LABEL (label),
00907 FALSE) ;
00908 gtk_label_set_use_underline (GTK_LABEL (label),
00909 FALSE) ;
00910 pgo_layout = gtk_label_get_layout (GTK_LABEL (label)) ;
00911
00912 wrap_width = a_text_box->inner_edge.max_width ;
00913
00914 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE) ;
00915 gtk_widget_set_size_request (label, wrap_width,
00916 -1) ;
00917
00918
00919
00920
00921 pgo_attr_list =
00922 pango_attr_list_new () ;
00923 g_return_val_if_fail (pgo_attr_list, CR_ERROR) ;
00924
00925 status = cr_style_to_pango_font_attributes
00926 (a_text_box->style, pgo_attr_list,
00927 strlen (a_text_box->content->u.text)) ;
00928
00929 gtk_label_set_attributes (GTK_LABEL (label), pgo_attr_list) ;
00930
00931 return status ;
00932 }
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 static enum CRStatus
00947 compute_and_set_box_dimensions (CRLayEng *a_this,
00948 CRBox *a_cur_box)
00949 {
00950 enum CRStatus status = CR_OK ;
00951
00952 g_return_val_if_fail (a_cur_box && a_cur_box->style,
00953 CR_BAD_PARAM_ERROR) ;
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974 a_cur_box->border_edge.x =
00975 a_cur_box->outer_edge.x
00976 +
00977 a_cur_box->style->num_props[NUM_PROP_MARGIN_LEFT].cv.val ;
00978 a_cur_box->border_edge.y =
00979 a_cur_box->outer_edge.y
00980 +
00981 a_cur_box->style->num_props[NUM_PROP_MARGIN_TOP].cv.val ;
00982
00983 a_cur_box->padding_edge.x =
00984 a_cur_box->border_edge.x
00985 +
00986 a_cur_box->style->num_props[NUM_PROP_BORDER_LEFT].cv.val ;
00987
00988 a_cur_box->padding_edge.y =
00989 a_cur_box->border_edge.y
00990 +
00991 a_cur_box->style->num_props[NUM_PROP_BORDER_TOP].cv.val ;
00992
00993
00994
00995
00996 a_cur_box->inner_edge.x =
00997 a_cur_box->padding_edge.x
00998 +
00999 a_cur_box->style->num_props[NUM_PROP_PADDING_LEFT].cv.val ;
01000 a_cur_box->inner_edge.y =
01001 a_cur_box->padding_edge.y
01002 +
01003 a_cur_box->style->num_props[NUM_PROP_PADDING_LEFT].cv.val ;
01004
01005
01006
01007
01008 a_cur_box->inner_edge.max_width =
01009 (a_cur_box->parent->inner_edge.x +
01010 a_cur_box->parent->inner_edge.max_width) -
01011 a_cur_box->inner_edge.x -
01012 (a_cur_box->style->num_props[NUM_PROP_MARGIN_RIGHT].cv.val
01013 + a_cur_box->style->num_props[NUM_PROP_BORDER_RIGHT].cv.val
01014 + a_cur_box->style->num_props[NUM_PROP_PADDING_RIGHT].cv.val) ;
01015
01016
01017
01018
01019 if (cr_num_is_fixed_length
01020 (&a_cur_box->style->num_props[NUM_PROP_WIDTH].cv) == TRUE)
01021 {
01022 a_cur_box->inner_edge.width =
01023 a_cur_box->style->num_props[NUM_PROP_WIDTH].cv.val ;
01024
01025 if (a_cur_box->inner_edge.max_width >
01026 a_cur_box->style->num_props[NUM_PROP_WIDTH].cv.val)
01027 {
01028 a_cur_box->inner_edge.max_width =
01029 a_cur_box->style->
01030 num_props[NUM_PROP_WIDTH].cv.val ;
01031 }
01032 }
01033
01034 if (a_cur_box->children)
01035 {
01036
01037
01038
01039
01040 status = layout_box (a_this, a_cur_box->children) ;
01041 g_return_val_if_fail (status == CR_OK, status) ;
01042 }
01043 else
01044 {
01045
01046
01047
01048
01049
01050
01051 if (a_cur_box->content)
01052 {
01053 switch (a_cur_box->content->type)
01054 {
01055 case TEXT_CONTENT_TYPE:
01056 if (a_cur_box->parent
01057 && cr_num_is_fixed_length
01058 (&a_cur_box->parent->style->
01059 num_props[NUM_PROP_WIDTH].cv))
01060 {
01061 cr_num_copy
01062 (&a_cur_box->style->
01063 num_props[NUM_PROP_WIDTH].cv,
01064 &a_cur_box->parent->style->
01065 num_props[NUM_PROP_WIDTH].cv) ;
01066 }
01067 layout_text_in_box (a_this, a_cur_box) ;
01068 compute_text_box_inner_edge_size
01069 (a_this, a_cur_box) ;
01070 break ;
01071
01072 case IMAGE_CONTENT_TYPE:
01073 cr_utils_trace_info
01074 ("image content not "
01075 "supported yet") ;
01076 break ;
01077 case NO_CONTENT_TYPE:
01078 cr_utils_trace_info
01079 ("incoherent box model. "
01080 "We should have either "
01081 "image or text here. "
01082 "found NO_CONTENT_TYPE "
01083 "intead") ;
01084 break ;
01085 default:
01086 cr_utils_trace_info
01087 ("Unknown content type") ;
01088 break ;
01089 }
01090 }
01091 }
01092
01093
01094
01095
01096
01097
01098
01099
01100 a_cur_box->padding_edge.width = a_cur_box->inner_edge.width +
01101 a_cur_box->style->num_props[NUM_PROP_PADDING_RIGHT].cv.val +
01102 a_cur_box->style->num_props[NUM_PROP_PADDING_LEFT].cv.val ;
01103 a_cur_box->padding_edge.height = a_cur_box->inner_edge.height +
01104 a_cur_box->style->num_props[NUM_PROP_PADDING_TOP].cv.val +
01105 a_cur_box->style->num_props[NUM_PROP_PADDING_BOTTOM].cv.val ;
01106
01107 a_cur_box->border_edge.width = a_cur_box->padding_edge.width +
01108 a_cur_box->style->num_props[NUM_PROP_BORDER_RIGHT].cv.val +
01109 a_cur_box->style->num_props[NUM_PROP_BORDER_LEFT].cv.val ;
01110 a_cur_box->border_edge.height = a_cur_box->padding_edge.height +
01111 a_cur_box->style->num_props[NUM_PROP_BORDER_TOP].cv.val +
01112 a_cur_box->style->num_props[NUM_PROP_BORDER_BOTTOM].cv.val ;
01113
01114 a_cur_box->outer_edge.width = a_cur_box->border_edge.width +
01115 a_cur_box->style->num_props[NUM_PROP_MARGIN_LEFT].cv.val +
01116 a_cur_box->style->num_props[NUM_PROP_MARGIN_RIGHT].cv.val ;
01117 a_cur_box->outer_edge.height = a_cur_box->border_edge.height +
01118 a_cur_box->style->num_props[NUM_PROP_MARGIN_TOP].cv.val +
01119 a_cur_box->style->num_props[NUM_PROP_MARGIN_BOTTOM].cv.val ;
01120
01121 if (a_cur_box->parent->inner_edge.child_rmost_x
01122 < a_cur_box->outer_edge.x + a_cur_box->outer_edge.width)
01123 {
01124 a_cur_box->parent->inner_edge.child_rmost_x =
01125 a_cur_box->outer_edge.x +
01126 a_cur_box->outer_edge.width ;
01127 }
01128
01129 return CR_OK ;
01130 }
01131
01132
01133
01134
01135
01136
01137
01138 static enum CRStatus
01139 adjust_parent_inner_edge_size (CRLayEng *a_this,
01140 CRBox *a_cur_box)
01141 {
01142 g_return_val_if_fail (a_cur_box
01143 && a_this
01144 && PRIVATE (a_this),
01145 CR_BAD_PARAM_ERROR) ;
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155 if (PRIVATE (a_this)->update_parent_box_size == TRUE
01156 && a_cur_box->parent)
01157 {
01158 gulong parent_inner_edge_right_bound =
01159 a_cur_box->parent->inner_edge.x +
01160 a_cur_box->parent->inner_edge.width ;
01161 gulong outer_edge_right_bound =
01162 a_cur_box->outer_edge.x +
01163 a_cur_box->outer_edge.width ;
01164
01165 if (parent_inner_edge_right_bound
01166 <
01167 outer_edge_right_bound)
01168 {
01169
01170
01171
01172
01173
01174 a_cur_box->parent->inner_edge.width =
01175 outer_edge_right_bound -
01176 a_cur_box->parent->inner_edge.x ;
01177 }
01178 }
01179
01180
01181
01182
01183
01184 if (a_cur_box->parent)
01185 {
01186 gulong parent_inner_edge_bottom_bound =
01187 a_cur_box->parent->inner_edge.y +
01188 a_cur_box->parent->inner_edge.height ;
01189 gulong outer_edge_bottom_bound =
01190 a_cur_box->outer_edge.y +
01191 a_cur_box->outer_edge.height ;
01192
01193 if (parent_inner_edge_bottom_bound <
01194 outer_edge_bottom_bound)
01195 {
01196 a_cur_box->parent->inner_edge.height =
01197 outer_edge_bottom_bound -
01198 a_cur_box->parent->inner_edge.y ;
01199 }
01200 }
01201
01202 return CR_OK ;
01203 }
01204
01205
01206
01207
01208
01209
01210
01211
01212 static enum CRStatus
01213 layout_block_box (CRLayEng *a_this,
01214 CRBox *a_cur_box)
01215 {
01216 enum CRStatus status = CR_OK ;
01217
01218 g_return_val_if_fail (a_cur_box && a_cur_box->style,
01219 CR_BAD_PARAM_ERROR) ;
01220
01221 CRBox *cont_box = a_cur_box->parent ;
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236 if (!cont_box)
01237 {
01238 a_cur_box->outer_edge.x = 0 ;
01239 a_cur_box->outer_edge.y = 0 ;
01240 a_cur_box->inner_edge.width = 800 ;
01241 a_cur_box->inner_edge.height = 600 ;
01242 a_cur_box->inner_edge.max_width = 800 ;
01243 }
01244 else
01245 {
01246 a_cur_box->outer_edge.x =
01247 cont_box->inner_edge.x ;
01248 if (a_cur_box->prev)
01249 {
01250 a_cur_box->outer_edge.y =
01251 get_box_bottommost_y (a_cur_box->prev) ;
01252 }
01253 else
01254 {
01255 a_cur_box->outer_edge.y =
01256 cont_box->inner_edge.y ;
01257 }
01258 }
01259
01260 g_return_val_if_fail (a_cur_box->parent->inner_edge.max_width
01261 + a_cur_box->parent->inner_edge.x
01262 > a_cur_box->outer_edge.x,
01263 CR_ERROR) ;
01264
01265 status = compute_and_set_box_dimensions (a_this,
01266 a_cur_box) ;
01267 return status ;
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278 static enum CRStatus
01279 layout_inline_box (CRLayEng *a_this,
01280 CRBox *a_cur_box)
01281 {
01282 CRBox *cont_box = NULL, *prev_box = NULL ;
01283 enum CRStatus status = CR_OK ;
01284
01285 g_return_val_if_fail (a_cur_box && a_cur_box->style,
01286 CR_BAD_PARAM_ERROR) ;
01287
01288 cont_box = a_cur_box->parent ;
01289 prev_box = a_cur_box->prev ;
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304 if (!prev_box)
01305 {
01306
01307
01308
01309
01310 if (cont_box)
01311 {
01312 a_cur_box->outer_edge.x = cont_box->inner_edge.x ;
01313 a_cur_box->outer_edge.y = cont_box->inner_edge.y ;
01314 }
01315 else
01316 {
01317
01318 a_cur_box->outer_edge.x = 0 ;
01319 a_cur_box->outer_edge.y = 0 ;
01320 }
01321 }
01322 else
01323 {
01324 a_cur_box->outer_edge.x =
01325 get_box_rightmost_x (prev_box) + 1 ;
01326 a_cur_box->outer_edge.y = prev_box->outer_edge.y ;
01327 }
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340 status = compute_and_set_box_dimensions (a_this,
01341 a_cur_box) ;
01342
01343 return status ;
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358 static enum CRStatus
01359 layout_box_in_normal_flow (CRLayEng *a_this,
01360 CRBox *a_cur_box)
01361 {
01362 enum CRStatus status = CR_OK ;
01363
01364 g_return_val_if_fail (a_cur_box && a_cur_box->style,
01365 CR_BAD_PARAM_ERROR) ;
01366
01367
01368
01369
01370
01371
01372 if (a_cur_box->style->position != POSITION_STATIC
01373 && a_cur_box->style->position != POSITION_RELATIVE)
01374 {
01375 return CR_UNEXPECTED_POSITION_SCHEME ;
01376 }
01377
01378
01379
01380
01381
01382 switch (a_cur_box->type)
01383 {
01384 case BOX_TYPE_BLOCK:
01385 case BOX_TYPE_ANONYMOUS_BLOCK:
01386 layout_block_box (a_this, a_cur_box) ;
01387 break ;
01388
01389 case BOX_TYPE_COMPACT:
01390 case BOX_TYPE_RUN_IN:
01391 case BOX_TYPE_INLINE:
01392 case BOX_TYPE_ANONYMOUS_INLINE:
01393 layout_inline_box (a_this, a_cur_box) ;
01394 break ;
01395
01396 default:
01397 break ;
01398 }
01399
01400
01401 return status ;
01402 }
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417 static enum CRStatus
01418 layout_box (CRLayEng *a_this,
01419 CRBox *a_cur_box)
01420 {
01421 CRBox *cur_box = NULL ;
01422
01423 g_return_val_if_fail (a_cur_box && a_cur_box->style,
01424 CR_BAD_PARAM_ERROR) ;
01425
01426 PRIVATE (a_this)->update_parent_box_size = TRUE ;
01427
01428 for (cur_box = a_cur_box ; cur_box ;
01429 cur_box = cur_box->next)
01430 {
01431 style_specified_2_computed_values (a_this, cur_box->style,
01432 cur_box->parent) ;
01433
01434 switch (cur_box->style->position)
01435 {
01436 case POSITION_STATIC:
01437 case POSITION_RELATIVE:
01438 layout_box_in_normal_flow
01439 (a_this, cur_box) ;
01440 break ;
01441
01442 case POSITION_ABSOLUTE:
01443 case POSITION_FIXED:
01444
01445 break ;
01446
01447 case POSITION_INHERIT:
01448 break ;
01449 }
01450
01451
01452
01453
01454
01455 adjust_parent_inner_edge_size (a_this,
01456 cur_box) ;
01457 }
01458
01459 return CR_OK ;
01460 }
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472 void
01473 cr_lay_eng_init (glong a_argc, gchar ** a_argv)
01474 {
01475
01476 if (gv_layeng_initialized == FALSE)
01477 {
01478 gtk_init ((int*)&a_argc, &a_argv) ;
01479 gv_layeng_initialized = TRUE ;
01480 }
01481 }
01482
01483
01484
01485
01486
01487
01488
01489 CRLayEng *
01490 cr_lay_eng_new (GtkLayout *a_layout)
01491 {
01492 CRLayEng *result = NULL ;
01493
01494 if (gv_layeng_initialized == FALSE)
01495 {
01496 cr_utils_trace_info ("Layout Engine must be initialized "
01497 "by calling cr_lay_eng_init() first") ;
01498 return NULL ;
01499 }
01500
01501 result = g_try_malloc (sizeof (CRLayEng)) ;
01502 if (!result)
01503 {
01504 cr_utils_trace_info ("Out of memory") ;
01505 return NULL ;
01506 }
01507 memset (result, 0, sizeof (CRLayEng)) ;
01508
01509 PRIVATE (result) = g_try_malloc (sizeof (CRLayEngPriv)) ;
01510 if (!PRIVATE (result))
01511 {
01512 cr_utils_trace_info ("Out of memory") ;
01513 g_free (result) ;
01514 result = NULL ;
01515 return NULL ;
01516 }
01517 memset (PRIVATE (result), 0, sizeof (CRLayEngPriv)) ;
01518
01519 PRIVATE (result)->layout = a_layout ;
01520
01521 PRIVATE (result)->xdpi = gdk_screen_width () /
01522 gdk_screen_width_mm () * 25.4 ;
01523 PRIVATE (result)->ydpi = gdk_screen_height () /
01524 gdk_screen_height_mm () * 25.4 ;
01525
01526 return result ;
01527 }
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538 enum CRStatus
01539 cr_lay_eng_create_box_model (CRLayEng *a_this,
01540 xmlDoc *a_doc,
01541 CRCascade *a_cascade,
01542 CRBoxModel **a_box_model)
01543 {
01544 xmlNode *root_node = NULL ;
01545 CRBox *box_tree = NULL;
01546
01547 g_return_val_if_fail (a_this && a_doc && a_cascade,
01548 CR_BAD_PARAM_ERROR) ;
01549
01550 root_node = xmlDocGetRootElement (a_doc) ;
01551
01552 if (!root_node)
01553 return CR_NO_ROOT_NODE_ERROR ;
01554
01555 PRIVATE (a_this)->cascade = a_cascade ;
01556
01557 if (!*a_box_model)
01558 {
01559 *a_box_model = cr_box_model_new () ;
01560 }
01561
01562 box_tree =
01563 create_box_tree_real (a_this, root_node,
01564 (CRBox*)*a_box_model) ;
01565
01566 if (box_tree)
01567 return CR_OK ;
01568 else
01569 return CR_ERROR ;
01570 }
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581 enum CRStatus
01582 cr_lay_eng_layout_box_tree (CRLayEng *a_this,
01583 CRBox *a_box_tree)
01584 {
01585 enum CRStatus status = CR_OK ;
01586
01587 g_return_val_if_fail (a_this && a_box_tree,
01588 CR_BAD_PARAM_ERROR) ;
01589
01590 status = layout_box (a_this, a_box_tree) ;
01591
01592 return status ;
01593 }
01594
01595
01596
01597
01598
01599
01600 void
01601 cr_lay_eng_destroy (CRLayEng *a_this)
01602 {
01603 g_return_if_fail (a_this) ;
01604
01605 if (PRIVATE (a_this)->sel_eng)
01606 {
01607 cr_sel_eng_destroy (PRIVATE (a_this)->sel_eng) ;
01608 PRIVATE (a_this)->sel_eng = NULL ;
01609 }
01610
01611 if (PRIVATE (a_this))
01612 {
01613 g_free (PRIVATE (a_this)) ;
01614 PRIVATE (a_this) = NULL ;
01615 }
01616
01617 if (a_this)
01618 {
01619 g_free (a_this) ;
01620 }
01621 }