Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

cr-lay-eng.c

Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
00002 
00003 /*
00004  * This file is part of The Croco Library
00005  *
00006  * Copyright (C) 2002-2003 Dodji Seketeli <dodji@seketeli.org>
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of version 2.1 of the 
00010  * GNU Lesser General Public
00011  * License as published by the Free Software Foundation.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the 
00019  * GNU Lesser General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022  * USA
00023  */
00024 
00025 /*
00026  *$Id: cr-lay-eng.c,v 1.20 2003/07/05 21:08:56 dodji Exp $
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  *@file
00039  *The definition of the #CRLayEng class.
00040  *Highly unstable and experimental so far.
00041  *This is in developement so the api is *really* gonna change ...
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 ;/*x resolution*/
00051         gulong ydpi ; /*y resolution*/
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  *Private methods.
00119  **********************/
00120 
00121 /**
00122  *Sets the box style values so that
00123  *it has no padding, no border, no margin.
00124  *The other style values are left as is cause
00125  *they must have been set prior to calling this
00126  *function.
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                 /*a_dest_num->type = NUM_LENGTH_PX ;*/
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                 /*1 inch == 25.4 mm*/
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                 /*1 inch == 25.4 mm*/
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                 /*1 point == 1/72 inch*/
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                 /*1 pica == 12 points*/
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          *walk thru the numerical properties (num_props) and 
00352          *compute their computed value.
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                                  *TODO: compute the computed value
00370                                  *using the parent box size.
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                                  *TODO: compute the computed value
00406                                  *using the parent box size.
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                                  *TODO: compute the computed value
00436                                  *using the parent box size.
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          *Now compute the specific css2 specification recommendations.
00487          *This can seem ugly, but it needs to be done. I do it here untill
00488          *I find a better place for it.
00489          ***************************************/
00490 
00491         /*
00492          *css2 spec chap 8.5.3 says that if border-style-x is set to
00493          *'none', it forces border-x to have a width of zero.
00494          *For the time being, we consider the 'none' and 'hidden' values
00495          *being equal untill be implement the support of table.
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  *Creates a box sub tree from an xml node tree.
00539  *@param a_this the current instance of #CRLayEng.
00540  *@param a_root_node the root node of the xml tree.
00541  *@param a_parent_box the root of the box tree to build.
00542  *@return the newly built box tree, or NULL if an error
00543  *happens.
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                 /*build here the node annotation*/
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                         /*here, build the box,
00600                          *append it to the box tree
00601                          *and update all it attributes but
00602                          *the positioning. The positioning will
00603                          *be updated later via the cr_box_layout() method.
00604                          */
00605                         /*style_specified_2_computed_values 
00606                           (a_this, style, a_parent_box) ;*/
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                          *store a pointer to the node that generated
00625                          *the current box into that current box.
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                                  *create here an anonymous box
00664                                  *which style inherits the style
00665                                  *of the parent box.
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                                  *by default, text/img boxes are inline.
00689                                  */
00690                                 cur_box->type = BOX_TYPE_INLINE ;
00691                                 cur_box->style->display = DISPLAY_INLINE ;
00692 
00693                                 /*
00694                                  *store a pointer to the node that generated
00695                                  *the current box into that current box.
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                                  *the anonymous box
00709                                  *must have no margin,
00710                                  *no padding, no border,
00711                                  *no border style, no offset
00712                                  */
00713                                 init_anonymous_text_box (cur_box) ;
00714 
00715                                 /*style_specified_2_computed_values 
00716                                   (a_this, cur_box->style, a_parent_box) ;*/
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                 /*walk through what remains from the tree*/
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  *Computes the abscissa of the rightmost side
00774  *of the current box.
00775  *@param a_box the current box.
00776  *@return a positve or 0 number if the computation went well,
00777  *-1 otherwise.
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  *computes the inner edge size of a box which
00795  *contents text only.
00796  *This fonction uses pango to compute the size
00797  *of the box. Note that layout_text_in_box must have
00798  *been called prior to this function.
00799  *Note that this is highly experimental for the time being.
00800  *It more a design sketch than a real working code.
00801  *@param a_this in/out parameter the current box which inner edge is to
00802  *be computed.
00803  *@return TRUE if the inner edge has been computed, FALSE otherwise.
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         /*gtk_widget_size_request (label, &requisition) ;*/
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          *TODO: set the font description attributes.
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  *Computes the size and positions of border edge, pading edge,
00936  *and inner edge. Also compute the size of the outer edge (aka margin edge).
00937  *All these calculations are done relatively to the position of the outer edge.
00938  *Which means that the position (x,y) of the outer edge *must* be set prior
00939  *to calling this function.
00940  *Note that this function calls layout_box() to compute the size of
00941  *the inner edge if it contains non terminal boxes.
00942  *@param a_this the layout engine.
00943  *@param a_cur_box the box.
00944  *@return CR_OK upon successfull completion, an error code otherwise.
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          *1/set the left border and 
00957          *left padding edges.
00958          *2/compute the left most x and topmost y of
00959          *the inner box.
00960          *3/compute the max_width of the inner edge.
00961          *
00962          *4/Compute the outer edge of the contained
00963          *box; this is recursive.
00964          *******************************************/
00965 
00966         /*
00967          *step 1/
00968          */
00969 
00970         /*
00971          *TODO: collapse this margin !!!.
00972          *See css2 chap 8.3.1 to see what "collapsing" means.
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          *Step 2/
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          *Step 3/
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          *Step 4.
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                  *layout the children boxes. This function call will
01038                  *also update the current inner_edge size.
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                  *this box may have a content.
01047                  *TODO: compute it's width and height.
01048                  *then, when computed, update the
01049                  *children max width size in the parent box.
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          *Inner edge position (x,y) and size computing is 
01095          *finished.
01096          *Now, we can compute the widths of the
01097          *remaining three other boxes 
01098          *(padding edge, border edge and outer edge)
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  *Adjusts the size of the inner edge of this box's parent.
01134  *That is, increases (if needed) the parent inner edge's width/height.
01135  *@param a_this the current instance of #CRBox.
01136  *@param a_cur_box the box to consider.
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         if (a_cur_box->parent 
01148             && a_cur_box->parent->style
01149             && (cr_num_is_fixed_length 
01150             (&a_cur_box->parent->style->num_props[NUM_PROP_WIDTH].cv) == TRUE))
01151         {
01152                 return CR_OK ;
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                          *parent inner edge is too short to
01171                          *contain this box outer edge.
01172                          *So, we just enlarge it.
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          *Make sure the parent inner_edge.heigth is big enough
01182          *to contain the current box.
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  *Layout a box in block formating context.
01207  *See css2 spec in chapters 9.2.
01208  *@param a_this the current instance of CRLayEng.
01209  *@param a_cur_box the current box to layout.
01210  *@return CR_OK upon successfull completion, an error code otherwise.
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          *We are in a block formating context 
01225          ************************************/
01226 
01227         /*
01228          *position the 'x' of the top
01229          *leftmost corner of this box
01230          *at the leftmost abscissa of it's
01231          *containing box.
01232          *Position the 'y' of
01233          *the top left corner of this
01234          *just under the previous box.
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  *Layout a box in an inline formating context.
01273  *See css2 spec in chapters 9.2.
01274  *@param a_this the layout engine.
01275  *@param a_cur_box the current box to layout.
01276  *@return CR_OK upon successfull completion, an error code otherwise.
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          *We are in an inline formating context 
01293          ************************************/
01294 
01295         /********************************************
01296          *position the 'x' of the top
01297          *leftmost corner of this box
01298          *one pixel right after the rightmost x
01299          *of the preceding box.
01300          *Position the 'y' of this box to
01301          *the y of the previous box.
01302          ********************************************/
01303 
01304         if (!prev_box)
01305         {
01306                 /*
01307                  *this box is the leftmost box contained in its containing
01308                  *box.
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                         /*this box does not have any containing box*/
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          *Now, compute the inner edge of this box;
01331          *which means 
01332          *1/set the left border and
01333          *left padding edges.
01334          *2/compute the left most x and topmost y of
01335          *the inner box and.
01336          *3/Compute the outer edge of the containing
01337          *box; this is recursive.
01338          *******************************************/                
01339 
01340         status = compute_and_set_box_dimensions (a_this,
01341                                                  a_cur_box) ;
01342 
01343         return status ;
01344 }
01345 
01346 /**
01347  *Lay the box out according to "Normal flow"
01348  *as decribed in css2 spec chap 9.4.
01349  *In normal flow, a box belongs to a formating context
01350  *that may be block or inline. In block formating context,
01351  *boxes are laid out verticaly, one under an other.
01352  *In inline formatting context, boxes are laid out horizontally,
01353  *usually from the left to the right, unless we support bidi.
01354  *@param a_this the layout engine.
01355  *@param a_cur_box the current box.
01356  *@return CR_OK upon successfull completion, an error code otherwise.
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          *Only boxes that have
01369          *the position rule set to 'static' or 'relative'
01370          *can be part of a normal formatting context.
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          *TODO
01380          *compute the "computed values" of the style data structure.
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  *Layout a box.
01407  *This function determine the  flow scheme (e.g: normal flow etc ...)
01408  *and call the right specialized function that knows how to perform
01409  *the layout according to that flow scheme.
01410  *Note that a flow scheme is local to a box. A child box can have a 
01411  *different flow scheme for example. So the lower level function called
01412  *by layout_box() can also call layout_box() to perform the layout of their
01413  *children boxes.
01414  *@param a_this the layout engine.
01415  *@param a_cur_box the current box.
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                         /*cr_box_layout_absolute (a_cur_box) ;*/
01445                         break ;
01446 
01447                 case POSITION_INHERIT:
01448                         break ;
01449                 }
01450                 
01451                 /*
01452                  *make sure the parent inner_edge is big enough to contain
01453                  *the current box.
01454                  */
01455                 adjust_parent_inner_edge_size (a_this,
01456                                                cur_box) ;
01457         }
01458         
01459         return CR_OK ;
01460 }
01461 
01462 /**********************
01463  *Public methods.
01464  **********************/
01465 
01466 /**
01467  *The first function to call prior to any other
01468  *method of the layout engine.
01469  *@param a_argc the argc parameter passed to the standard C main entry point.
01470  *@param a_argv the argv parameter passed to the standard C main entry point.
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  *Instanciates a new Layout Engine.
01486  *return the new instance of #CRLayEng or NULL if
01487  *an error occured.
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  *Creates the box model from an xml document.
01531  *@param a_this the current instance of #CRLayEng.
01532  *@param a_doc the current xml document.
01533  *@param a_cascade the css2 stylesheet cascade.
01534  *@param a_box_model out parameter. The returned
01535  *@return CR_OK upon successfull completion, an error code
01536  *otherwise.
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  *Recursively computes the sizes and positions of each
01576  *box in the box tree.
01577  *@param a_this
01578  *@param a_box_tree
01579  *@return
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  *Destuctor of #CRLayEng.
01598  *@param a_this the current instance of #CRLayEng.
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 }

Generated on Wed Oct 1 01:36:45 2003 for Libcroco by doxygen 1.3.3