home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / laycols.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  20.8 KB  |  845 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "xp.h"
  20. #include "pa_parse.h"
  21. #include "layout.h"
  22. #include "laylayer.h"
  23. #include "layers.h"
  24.  
  25.  
  26. #define MULTICOL_MIN_WIDTH    10
  27. #define MULTICOL_GUTTER_WIDTH    10
  28.  
  29. void lo_StartMultiColInit( lo_DocState *state, lo_MultiCol *multicol )
  30. {
  31.     multicol->end_last_line = state->end_last_line;
  32.     multicol->start_ele = state->top_state->element_id;
  33.     multicol->start_line = state->line_num;
  34.     multicol->end_line = multicol->start_line;
  35.     multicol->start_x = state->x;
  36.     multicol->start_y = state->y;
  37.     multicol->end_y = multicol->start_y;
  38. }
  39.  
  40. void lo_SetupStateForBeginMulticol( lo_DocState *state, lo_MultiCol *multicol, int32 doc_width )
  41. {
  42.     int32 width;
  43.  
  44.     /* Temporary create a tag on the stack to avoid recompile of everything!  Make sure that this tag should be passed in as
  45.        a parameter before checking in.*/
  46.     PA_Tag tag;
  47.  
  48.     tag.type = P_MULTICOLUMN;
  49.     tag.is_end = FALSE;
  50.  
  51.     /* If absolute width specifed set width to that, else set it to full screen */
  52.     if (!multicol->isPercentWidth && multicol->width > 0)
  53.         width = multicol->width;
  54.     else 
  55.         width = doc_width;
  56.  
  57.     /* If percent width specified, set width to correct % of current doc_width */
  58.     if (multicol->isPercentWidth) {
  59.         int32 val = multicol->width;
  60.         
  61.         if (state->allow_percent_width == FALSE) {
  62.             val = 0;
  63.         }
  64.         else {
  65.             val = doc_width * val / 100;
  66.             if (val < 1)
  67.             {
  68.                 val = 1;
  69.             }
  70.         }
  71.         width = val;
  72.     }
  73.  
  74.     width = width - ((multicol->cols - 1) * multicol->gutter);
  75.     multicol->col_width = width / multicol->cols;
  76.     if (multicol->col_width < MULTICOL_MIN_WIDTH)
  77.     {
  78.         multicol->col_width = MULTICOL_MIN_WIDTH;
  79.     }
  80.  
  81.     multicol->orig_margin = state->right_margin;
  82.  
  83.     lo_PushList(state, &tag, QUOTE_NONE);
  84.  
  85.     state->right_margin = state->left_margin + multicol->col_width;
  86.     state->x = state->left_margin;
  87.     state->list_stack->old_left_margin = state->left_margin;
  88.     state->list_stack->old_right_margin = state->right_margin;
  89.  
  90.     multicol->orig_min_width = state->min_width;
  91.     state->min_width = 0;
  92.  
  93.     /*
  94.      * Don't display anything while processing the multicolumn text.
  95.      */
  96.     multicol->orig_display_blocking_element_y = state->display_blocking_element_y;
  97.     state->display_blocking_element_y = -1;
  98.     multicol->orig_display_blocked = state->display_blocked;
  99.     state->display_blocked = TRUE;
  100.  
  101.     multicol->next = state->current_multicol;
  102.     state->current_multicol = multicol;
  103. }
  104.  
  105. void lo_AppendMultiColToLineList (MWContext *context, lo_DocState *state, LO_MulticolumnStruct *multicol)
  106. {
  107.   multicol->lo_any.ele_id = NEXT_ELEMENT;
  108.   multicol->lo_any.x = state->x;
  109.   multicol->lo_any.y = state->y;
  110.  
  111.   lo_AppendToLineList(context, state, (LO_Element*)multicol, 0);
  112. }
  113.  
  114. /* Appends a zero width and height line feed to state->line_list.  Flushes line list into line array */
  115. void lo_AppendZeroWidthAndHeightLF(MWContext *context, lo_DocState *state)
  116. {
  117.     LO_LinefeedStruct *lf;
  118.  
  119.     lf = lo_NewLinefeed(state, context, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE);
  120.     lf->width = 0;
  121.     lf->height = 0;
  122.     lf->line_height = 0;
  123.     lo_AppendToLineList(context, state, (LO_Element *) lf, 0);
  124.     lo_AppendLineListToLineArray(context, state, (LO_Element *) lf);
  125. }
  126.  
  127.  
  128. void
  129. lo_BeginMulticolumn(MWContext *context, lo_DocState *state, PA_Tag *tag, LO_MulticolumnStruct *multicolEle)
  130. {
  131.     lo_MultiCol *multicol;
  132.     PA_Block buff;
  133.     char *str;
  134.     int32 val;
  135.     int32 doc_width;
  136.     /* int32 width; */
  137.  
  138.     multicol = XP_NEW(lo_MultiCol);
  139.     if (multicol == NULL)
  140.     {
  141.         state->top_state->out_of_memory = TRUE;
  142.         return;
  143.     }
  144.  
  145.     multicol->width = 0;
  146.     multicol->isPercentWidth = FALSE;    
  147.  
  148.     /* Put a pointer to lo_multicol inside the MULTICOLUMN layout element that will be placed on the
  149.        line list */
  150.     multicolEle->multicol = multicol;
  151.     
  152.     /*
  153.      * If this multicol is within a layer, then we have to create an
  154.      * artificial TABLE around it (since the multicol code depends on
  155.      * the state's line array, which isn't in an updated state within
  156.      * a layer). 
  157.      */
  158.     if (state->layer_nest_level > 0)
  159.     {
  160.         PA_Tag *tmp_tag;
  161.         lo_TableRec *table;
  162.  
  163.         if (state->in_paragraph != FALSE)
  164.         {
  165.             lo_CloseParagraph(context, &state, tag, 2);
  166.         }
  167.  
  168.         lo_BeginTableAttributes(context, state, NULL, NULL, NULL, NULL,
  169.                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  170.                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  171.                                 NULL, NULL, NULL);
  172.         
  173.         table = state->current_table;
  174.         if (table) {
  175.             lo_BeginTableRowAttributes(context, state, table,
  176.                                        NULL, NULL, NULL, NULL);
  177.  
  178.             lo_BeginTableCellAttributes(context, state, table,
  179.                                         NULL, NULL, NULL, NULL, NULL,
  180.                                         LO_TILE_BOTH, NULL, NULL, NULL, NULL,
  181.                                         FALSE, TRUE);
  182.  
  183.             /* 
  184.              * If we've successfully created a subdoc, we need to clone
  185.              * the MULTICOL tag and save it in the subdoc, since the code
  186.              * above us doesn't realize we're now in a table.
  187.              */
  188.             if (state->sub_state) {
  189.                 state = state->sub_state;
  190.                 tmp_tag = PA_CloneMDLTag(tag);
  191.                 lo_SaveSubdocTags(context, state, tmp_tag);
  192.             }
  193.             multicol->close_table = TRUE;
  194.         }
  195.     }
  196.     else {        
  197.         /* if (line will not be flushed by lo_SetSoftLineBreak) and (there exist some elements on the line list) */
  198.         if (state->linefeed_state >= 2 && state->line_list != NULL)
  199.         {
  200.             /* Append zero width and height line feed to the line list and flush the line list into
  201.                the line array. This forces the layout of elements contained within the MULTICOL tags
  202.                to start on a blank line_list and hence on a new line.  lo_EndMultiColumn needs this to
  203.                do its line array hacking properly. */
  204.             lo_AppendZeroWidthAndHeightLF(context, state);            
  205.         }
  206.  
  207.         lo_SetSoftLineBreakState(context, state, FALSE, 2);
  208.         multicol->close_table = FALSE;        
  209.     }
  210.  
  211.     /*
  212.      * Since we are going to block layout during multicol
  213.      * processing, we need to flush the compositor of any
  214.      * pending displays.
  215.      */
  216.     if (context->compositor)
  217.     {
  218.         CL_CompositeNow(context->compositor);
  219.     }
  220.  
  221.     lo_StartMultiColInit( state, multicol );
  222.  
  223.     /*
  224.     multicol->end_last_line = state->end_last_line;
  225.     multicol->start_ele = state->top_state->element_id;
  226.     multicol->start_line = state->line_num;
  227.     multicol->end_line = multicol->start_line;
  228.     multicol->start_x = state->x;
  229.     multicol->start_y = state->y;
  230.     multicol->end_y = multicol->start_y;
  231.     */
  232.     multicol->cols = 1;
  233.     multicol->gutter = MULTICOL_GUTTER_WIDTH;
  234.  
  235.     /*    
  236.      * Get the cols parameter.
  237.      */
  238.     buff = lo_FetchParamValue(context, tag, PARAM_COLS);
  239.     if (buff != NULL)
  240.     {
  241.         PA_LOCK(str, char *, buff);
  242.         multicol->cols = XP_ATOI(str);
  243.         PA_UNLOCK(buff);
  244.         PA_FREE(buff);
  245.     }
  246.  
  247.     if (multicol->cols <= 1)
  248.     {
  249.         XP_DELETE(multicol);
  250.         multicolEle->multicol = NULL;
  251.         return;
  252.     }
  253.  
  254.     /*
  255.      * Get the gutter parameter.
  256.      */
  257.     buff = lo_FetchParamValue(context, tag, PARAM_GUTTER);
  258.     if (buff != NULL)
  259.     {
  260.         PA_LOCK(str, char *, buff);
  261.         multicol->gutter = XP_ATOI(str);
  262.         if (multicol->gutter < 1)
  263.         {
  264.             multicol->gutter = 1;
  265.         }
  266.         PA_UNLOCK(buff);
  267.         PA_FREE(buff);
  268.     }
  269.  
  270.     multicol->gutter = FEUNITS_X(multicol->gutter, context);
  271.  
  272.     doc_width = state->right_margin - state->left_margin;
  273.     /* width = doc_width; */
  274.  
  275.     /*
  276.      * Get the width parameter, in absolute or percentage.
  277.      * If percentage, make it absolute.
  278.      */
  279.     /*
  280.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  281.     if (buff != NULL)
  282.     {
  283.         Bool is_percent;
  284.  
  285.         PA_LOCK(str, char *, buff);
  286.         val = lo_ValueOrPercent(str, &is_percent);
  287.         if (is_percent != FALSE)
  288.         {
  289.             if (state->allow_percent_width == FALSE)
  290.             {
  291.                 val = 0;
  292.             }
  293.             else
  294.             {
  295.                 val = doc_width * val / 100;
  296.                 if (val < 1)
  297.                 {
  298.                     val = 1;
  299.                 }
  300.             }
  301.         }
  302.         else
  303.         {
  304.             val = FEUNITS_X(val, context);
  305.             if (val < 1)
  306.             {
  307.                 val = 1;
  308.             }
  309.         }
  310.         width = val;
  311.         PA_UNLOCK(buff);
  312.         PA_FREE(buff);
  313.     }
  314.     */
  315.  
  316.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  317.     if (buff != NULL)
  318.     {
  319.         Bool is_percent;
  320.  
  321.         PA_LOCK(str, char *, buff);
  322.         val = lo_ValueOrPercent(str, &is_percent);
  323.         if (is_percent != FALSE)
  324.         {
  325.             multicol->width = val;
  326.             multicol->isPercentWidth = TRUE;
  327.         }
  328.         else
  329.         {
  330.             multicol->width = val;
  331.             multicol->isPercentWidth = FALSE;
  332.             val = FEUNITS_X(val, context);
  333.             if (val < 1)
  334.             {
  335.                 val = 1;
  336.             }
  337.         }
  338.         PA_UNLOCK(buff);
  339.         PA_FREE(buff);
  340.     }
  341.  
  342.     /*
  343.     width = width - ((multicol->cols - 1) * multicol->gutter);
  344.     multicol->col_width = width / multicol->cols;
  345.     if (multicol->col_width < MULTICOL_MIN_WIDTH)
  346.     {
  347.         multicol->col_width = MULTICOL_MIN_WIDTH;
  348.     }
  349.  
  350.     multicol->orig_margin = state->right_margin;
  351.  
  352.     lo_PushList(state, tag, QUOTE_NONE);
  353. */
  354.  
  355.     lo_SetupStateForBeginMulticol( state, multicol, doc_width );
  356.     
  357.     /*
  358.     state->right_margin = state->left_margin + multicol->col_width;
  359.     state->x = state->left_margin;
  360.     state->list_stack->old_left_margin = state->left_margin;
  361.     state->list_stack->old_right_margin = state->right_margin;
  362.  
  363.     multicol->orig_min_width = state->min_width;
  364.     state->min_width = 0;
  365.     */
  366.  
  367.     /*
  368.      * Don't display anything while processing the multicolumn text.
  369.      */
  370.     /*
  371.     multicol->orig_display_blocking_element_y = state->display_blocking_element_y;
  372.     state->display_blocking_element_y = -1;
  373.     multicol->orig_display_blocked = state->display_blocked;
  374.     state->display_blocked = TRUE;
  375.  
  376.     multicol->next = state->current_multicol;
  377.     state->current_multicol = multicol;
  378.     */
  379. }
  380.  
  381.  
  382. static LO_Element *
  383. lo_capture_floating_elements(MWContext *context, lo_DocState *state,
  384.         int32 ele1, int32 ele2, int32 top_y, int32 bottom_y,
  385.         int32 *max_y)
  386. {
  387.     LO_Element *prev_eptr;
  388.     LO_Element *eptr;
  389.     LO_Element *float_list;
  390.  
  391.     *max_y = bottom_y;
  392.     float_list = NULL;
  393.     prev_eptr = NULL;
  394.     eptr = state->float_list;
  395.     while (eptr != NULL)
  396.     {
  397.         LO_Element *element;
  398.  
  399.         if (((eptr->lo_any.y >= top_y)&&
  400.              (eptr->lo_any.y < bottom_y))||
  401.             ((eptr->lo_any.ele_id >= ele1)&&
  402.              (eptr->lo_any.ele_id <= ele2)))
  403.         {
  404.             int32 my_y;
  405.  
  406.             element = eptr;
  407.             if (prev_eptr != NULL)
  408.             {
  409.                 prev_eptr->lo_any.next = eptr->lo_any.next;
  410.             }
  411.             else if (eptr == state->float_list)
  412.             {
  413.                 state->float_list = eptr->lo_any.next;
  414.             }
  415.             eptr = eptr->lo_any.next;
  416.  
  417.             element->lo_any.next = float_list;
  418.             float_list = element;
  419.  
  420.             my_y = element->lo_any.y +
  421.                 element->lo_any.y_offset +
  422.                 element->lo_any.height;
  423.             if (element->type == LO_IMAGE)
  424.             {
  425.                 /*
  426.                  * Images need to account for border width
  427.                  */
  428.                 my_y = my_y +
  429.                     (2 * element->lo_image.border_width);
  430.             }
  431.             if (my_y > *max_y)
  432.             {
  433.                 *max_y = my_y;
  434.             }
  435.         }
  436.         else
  437.         {
  438.             prev_eptr = eptr;
  439.             eptr = eptr->lo_any.next;
  440.         }
  441.     }
  442.  
  443.     return(float_list);
  444. }
  445.  
  446.  
  447. LO_CellStruct *
  448. lo_CaptureLines(MWContext *context, lo_DocState *state, int32 col_width,
  449.         int32 line1, int32 line2, int32 dx, int32 dy)
  450. {
  451.     int32 height, max_y;
  452.     int32 ele1, ele2;
  453.     LO_Element *eptr;
  454.     LO_Element *last_eptr;
  455.     LO_Element *past_eptr;
  456.     LO_CellStruct *cell;
  457.  
  458.     eptr = lo_FirstElementOfLine(context, state, line1);
  459.     if (eptr == NULL)
  460.     {
  461.         return(NULL);
  462.     }
  463.  
  464.     last_eptr = NULL;
  465.     past_eptr = lo_FirstElementOfLine(context, state, (line2 + 1));
  466.     if (past_eptr != NULL)
  467.     {
  468.         last_eptr = past_eptr->lo_any.prev;
  469.     }
  470.  
  471.     if (last_eptr == NULL)
  472.     {
  473.         last_eptr = lo_FirstElementOfLine(context, state, line2);
  474.         if (last_eptr == NULL)
  475.         {
  476.             last_eptr = eptr;
  477.         }
  478.         while (last_eptr->lo_any.next != NULL)
  479.         {
  480.             last_eptr = last_eptr->lo_any.next;
  481.         }
  482.     }
  483.  
  484.     if (past_eptr != NULL)
  485.     {
  486.         height = past_eptr->lo_any.y - eptr->lo_any.y;
  487.     }
  488.     else
  489.     {
  490.         height = last_eptr->lo_any.y + last_eptr->lo_any.line_height -
  491.                 eptr->lo_any.y;
  492.     }
  493.  
  494.     cell = (LO_CellStruct *)lo_NewElement(context, state, LO_CELL, NULL, 0);
  495.     if (cell == NULL)
  496.     {
  497.         state->top_state->out_of_memory = TRUE;
  498.         return(NULL);
  499.     }
  500.  
  501.     cell->type = LO_CELL;
  502.     cell->ele_id = NEXT_ELEMENT;
  503.     cell->x = eptr->lo_any.x + dx;
  504.     cell->x_offset = 0;
  505.     cell->y = eptr->lo_any.y + dy;
  506.     cell->y_offset = 0;
  507.     cell->width = col_width;
  508.     cell->height = height;
  509.     cell->next = NULL;
  510.     cell->prev = NULL;
  511.     cell->FE_Data = NULL;
  512.     cell->cell_float_list = NULL;
  513.     cell->backdrop.bg_color = NULL;
  514.         cell->backdrop.url = NULL;
  515.     cell->border_width = 0;
  516.     cell->border_vert_space = 0;
  517.     cell->border_horiz_space = 0;
  518.     cell->ele_attrmask = 0;
  519.     cell->sel_start = -1;
  520.     cell->sel_end = -1;
  521.     cell->cell_list = eptr;
  522.     cell->cell_list_end = last_eptr;
  523.     cell->cell_bg_layer = NULL;
  524.     cell->cell_inflow_layer = NULL;
  525.     cell->table_cell = NULL;
  526.     cell->table_row = NULL;
  527.     cell->table = NULL;
  528.  
  529.     if (eptr->lo_any.prev != NULL)
  530.     {
  531.         eptr->lo_any.prev->lo_any.next = NULL;
  532.         eptr->lo_any.prev = NULL;
  533.     }
  534.     if (last_eptr->lo_any.next != NULL)
  535.     {
  536.         last_eptr->lo_any.next->lo_any.prev = NULL;
  537.         last_eptr->lo_any.next = NULL;
  538.     }
  539.  
  540.     ele1 = eptr->lo_any.ele_id;
  541.     ele2 = last_eptr->lo_any.ele_id;
  542.  
  543.     cell->cell_float_list = lo_capture_floating_elements(context, state,
  544.         ele1, ele2, eptr->lo_any.y, (eptr->lo_any.y + height), &max_y);
  545.     if ((max_y - eptr->lo_any.y) > cell->height)
  546.     {
  547.         cell->height = max_y - eptr->lo_any.y;
  548.     }
  549.  
  550.     lo_ShiftCell(cell, dx, dy);
  551.  
  552.     return(cell);
  553. }
  554.  
  555.  
  556. static int32
  557. lo_find_breaking_line(MWContext *context, lo_DocState *state,
  558.             int32 start_line, int32 start_x, int32 end_x)
  559. {
  560.     LO_Element *eptr;
  561.     int32 line;
  562.  
  563.     /*
  564.      * Now that we overuse the BREAKABLE bitflag, this
  565.      * is easy, any line whose linefeed has that flag set
  566.      * is a breakable line.
  567.      */
  568.     line = start_line + 1;
  569.     eptr = lo_FirstElementOfLine(context, state, line);
  570.     while (eptr != NULL)
  571.     {
  572.         LO_Element *tmp_eptr;
  573.  
  574.         tmp_eptr = eptr;
  575.         while ((tmp_eptr != NULL)&&
  576.             (tmp_eptr->type != LO_LINEFEED))
  577.         {
  578.             tmp_eptr = tmp_eptr->lo_any.next;
  579.         }
  580.         if ((tmp_eptr != NULL)&&
  581.             (tmp_eptr->lo_linefeed.ele_attrmask & LO_ELE_BREAKABLE))
  582.         {
  583.             return(line - 1);
  584.         }
  585.         line++;
  586.         eptr = lo_FirstElementOfLine(context, state, line);
  587.     }
  588.     return(line - 1);
  589. }
  590.  
  591.  
  592. void
  593. lo_EndMulticolumn(MWContext *context, lo_DocState *state, PA_Tag *tag,
  594.             lo_MultiCol *multicol, Bool relayout)
  595. {
  596.     int32 i;
  597.     lo_ListStack *lptr;
  598.     int32 height;
  599.     int32 col_height;
  600.     int32 x, y;
  601.     int32 line1, line2;
  602.     int32 save_doc_min_width;
  603.     int32 min_multi_width;
  604.     LO_Element *cell_list;
  605.     LO_Element *cell_list_end;
  606.     LO_Element *cell_ele;
  607.     LO_TableStruct *table_ele;
  608.     LO_Element *ele;
  609.  
  610.     cell_ele = NULL;
  611.     cell_list = NULL;
  612.     cell_list_end = NULL;
  613.     
  614.     lo_SetLineBreakState (context, state, FALSE, LO_LINEFEED_BREAK_SOFT, 1, relayout);
  615.  
  616.     multicol->end_line = state->line_num;
  617.     multicol->end_y = state->y;
  618.  
  619.     /*
  620.      * Break to clear all left and right margins.
  621.      */
  622.     lo_ClearToBothMargins(context, state);
  623.  
  624.     /*
  625.      * Reset the margins properly in case
  626.      * we are inside a list.
  627.      */
  628.     lo_FindLineMargins(context, state, !relayout);
  629.     state->x = state->left_margin;
  630.  
  631.     height = multicol->end_y - multicol->start_y;
  632.     col_height = height / multicol->cols;
  633.     if (col_height < 1)
  634.     {
  635.         col_height = 1;
  636.     }
  637.  
  638.     x = state->x;
  639.     y = multicol->start_y;
  640.     line1 = multicol->start_line - 1;
  641.     for (i=0; i<multicol->cols; i++)
  642.     {
  643.         LO_CellStruct *cell;
  644.         LO_Element *eptr;
  645.         int32 line;
  646.         int32 dx, dy;
  647.         int32 move_height;
  648.  
  649.         eptr = lo_FirstElementOfLine(context, state, line1);
  650.         if (eptr == NULL)
  651.         {
  652.             break;
  653.         }
  654.         y = eptr->lo_any.y + col_height;
  655.  
  656.         line = lo_PointToLine(context, state, x, y);
  657.         eptr = lo_FirstElementOfLine(context, state, line);
  658.         if (eptr->lo_any.x > multicol->start_x)
  659.         {
  660.             line = lo_find_breaking_line(context, state, line,
  661.                 multicol->start_x,
  662.                 (multicol->start_x + multicol->col_width));
  663.         }
  664.  
  665.         line2 = line;
  666.         if (line2 > (multicol->end_line - 2))
  667.         {
  668.             line2 = (multicol->end_line - 2);
  669.         }
  670.         cell = NULL;
  671.         if (i > 0)
  672.         {
  673.             eptr = lo_FirstElementOfLine(context, state, line1);
  674.             if (eptr != NULL)
  675.             {
  676.                 dx = i * (multicol->col_width +
  677.                         multicol->gutter);
  678.                 dy = multicol->start_y - eptr->lo_any.y;
  679.                 cell = lo_CaptureLines(context, state,
  680.                     multicol->col_width,
  681.                     line1, line2, dx, dy);
  682.                 if (cell == NULL)
  683.                 {
  684.                     move_height = 0;
  685.                 }
  686.                 else
  687.                 {
  688.                     move_height = cell->height - 1;
  689.                 }
  690.             }
  691.             else
  692.             {
  693.                 move_height = 0;
  694.             }
  695.         }
  696.         else
  697.         {
  698.             cell = lo_CaptureLines(context, state,
  699.                 multicol->col_width,
  700.                 line1, line2, 0, 0);
  701.             if (cell == NULL)
  702.             {
  703.                 move_height = 0;
  704.             }
  705.             else
  706.             {
  707.                 move_height = cell->height - 1;
  708.             }
  709.         }
  710.         line1 = line2 + 1;
  711.         if (move_height > col_height)
  712.         {
  713.             col_height = move_height;
  714.         }
  715.  
  716.         if (cell != NULL)
  717.         {
  718.             if (cell_list_end == NULL)
  719.             {
  720.                 cell_list = (LO_Element *)cell;
  721.                 cell_list_end = cell_list;
  722.             }
  723.             else
  724.             {
  725.                 cell_list_end->lo_any.next = (LO_Element *)cell;
  726.                 cell_list_end = cell_list_end->lo_any.next;
  727.             }
  728.         }
  729.     }
  730.  
  731.     lptr = lo_PopList(state, tag);
  732.     if (lptr != NULL)
  733.     {
  734.         XP_DELETE(lptr);
  735.     }
  736.     state->left_margin = state->list_stack->old_left_margin;
  737.     state->right_margin = state->list_stack->old_right_margin;
  738.  
  739.     state->top_state->element_id = multicol->start_ele;
  740.  
  741.     lo_SetLineArrayEntry(state, NULL, (multicol->start_line - 1));
  742.     state->line_num = multicol->start_line;
  743.     state->end_last_line = multicol->end_last_line;
  744.     if (state->end_last_line != NULL)
  745.     {
  746.         state->end_last_line->lo_any.next = NULL;
  747.     }
  748.     state->line_list = NULL;
  749.     state->y = multicol->start_y;
  750.  
  751.     state->display_blocked = multicol->orig_display_blocked;
  752.     state->display_blocking_element_y = multicol->orig_display_blocking_element_y;
  753.  
  754.     table_ele = (LO_TableStruct *)lo_NewElement(context, state, LO_TABLE,
  755.                     NULL, 0);
  756.     if (table_ele == NULL)
  757.     {
  758.         state->top_state->out_of_memory = TRUE;
  759.         if (multicol->close_table)
  760.             lo_CloseTable(context, state);
  761.         return;
  762.     }
  763.  
  764.     table_ele->type = LO_TABLE;
  765.     table_ele->ele_id = NEXT_ELEMENT;
  766.     table_ele->x = x;
  767.     table_ele->x_offset = 0;
  768.     table_ele->y = multicol->start_y;
  769.     table_ele->y_offset = 0;
  770.     table_ele->width = (multicol->cols * multicol->col_width) +
  771.                 ((multicol->cols - 1) * multicol->gutter);
  772.     table_ele->height = col_height + 1;
  773.     table_ele->line_height = col_height + 1;
  774.     table_ele->FE_Data = NULL;
  775.     table_ele->anchor_href = NULL;
  776.     table_ele->alignment = LO_ALIGN_LEFT;
  777.     table_ele->border_width = 0;
  778.     table_ele->border_vert_space = 0;
  779.     table_ele->border_horiz_space = 0;
  780.     table_ele->border_style = BORDER_NONE;
  781.     table_ele->ele_attrmask = 0;
  782.     table_ele->sel_start = -1;
  783.     table_ele->sel_end = -1;
  784.     table_ele->next = NULL;
  785.     table_ele->prev = NULL;
  786.     table_ele->table = NULL;
  787.     lo_AppendToLineList(context, state, (LO_Element *)table_ele, 0);
  788.  
  789.     while (cell_list != NULL)
  790.     {
  791.         cell_ele = cell_list;
  792.         cell_list = cell_list->lo_any.next;
  793.         cell_ele->lo_any.next = NULL;
  794.         cell_ele->lo_any.ele_id = NEXT_ELEMENT;
  795.         lo_RenumberCell(state, (LO_CellStruct *)cell_ele);
  796.         lo_AppendToLineList(context, state, cell_ele, 0);
  797.     }
  798.  
  799.     if (cell_ele != NULL)
  800.     {
  801.         state->x = cell_ele->lo_any.x + multicol->col_width;
  802.     }
  803.     else
  804.     {
  805.         state->x = table_ele->x + table_ele->width;
  806.     }
  807.     state->baseline = 0;
  808.     state->line_height = col_height + 1;
  809.     state->linefeed_state = 0;
  810.     state->at_begin_line = FALSE;
  811.     state->trailing_space = FALSE;
  812.     state->cur_ele_type = LO_SUBDOC;
  813.  
  814.  
  815.     min_multi_width = (state->min_width * multicol->cols) +
  816.                 ((multicol->cols - 1) * multicol->gutter);
  817.     state->min_width = multicol->orig_min_width;
  818.     save_doc_min_width = state->min_width;
  819.  
  820.     lo_SetLineBreakState (context, state, FALSE, LO_LINEFEED_BREAK_SOFT, 2, relayout);
  821.  
  822.     if (min_multi_width > save_doc_min_width)
  823.     {
  824.         save_doc_min_width = min_multi_width;
  825.     }
  826.     state->min_width = save_doc_min_width;
  827.  
  828.     state->current_multicol = multicol->next;
  829.  
  830.     if (!relayout)
  831.     {
  832.         if (multicol->close_table) {
  833.             PA_Tag *tmp_tag;
  834.             if (state->in_paragraph != FALSE)
  835.             {
  836.                 lo_CloseParagraph(context, &state, tag, 2);
  837.             }
  838.             tmp_tag = PA_CloneMDLTag(tag); 
  839.             lo_SaveSubdocTags(context, state, tmp_tag);
  840.             lo_CloseTable(context, state);
  841.         }
  842.     }
  843. }
  844.  
  845.