home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / laystyle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  24.2 KB  |  961 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.  
  20. /*
  21.  * STYLE tag support.
  22.  */
  23.  
  24. #include "xp.h"
  25. #include "libmocha.h"
  26. #include "lo_ele.h"
  27. #include "pa_parse.h"
  28. #include "pa_tags.h"
  29. #include "layout.h"
  30. #include "laylayer.h"
  31. #include "laystyle.h"
  32. #include "prefapi.h"
  33. #include "css.h"
  34. #include "intl_csi.h"
  35.  
  36. void
  37. LO_SetStyleObjectRefs(MWContext *context, void *tags, void *classes, void *ids)
  38. {
  39.     lo_TopState    *top_state;
  40.  
  41.     LO_LockLayout();
  42.     top_state = lo_FetchTopState(XP_DOCID(context));
  43.     if (top_state && top_state->style_stack) {
  44.         SML_SetObjectRefs(top_state->style_stack, tags, classes, ids);
  45.     }
  46.     LO_UnlockLayout();
  47. }
  48.  
  49. #define _STYLE_GET_WIDTH  0
  50. #define _STYLE_GET_HEIGHT 1
  51.  
  52. char *
  53. lo_ParseStyleSheetURL(char *url_string)
  54. {
  55.     if(!url_string)
  56.         return NULL;
  57.  
  58.     /* look for url() around the url and strip it off */
  59.     if(!strncasecomp(url_string, "url(", 4))
  60.     {
  61.         int end;
  62.         url_string += 4; /* skip past "url(" */
  63.         
  64.         end = XP_STRLEN(url_string)-1;
  65.         /* strip the ")" */
  66.         if(url_string[end] == ')')
  67.             url_string[end] = '\0';
  68.     }
  69.  
  70.     return url_string;
  71. }
  72.  
  73. PRIVATE int32
  74. lo_get_font_height(MWContext *context, lo_DocState *state)
  75. {
  76.     int32 font_height = state->text_info.ascent +
  77.                                state->text_info.descent;
  78.  
  79.     if ((font_height <= 0)&&(state->font_stack != NULL)&&
  80.         (state->font_stack->text_attr != NULL))
  81.     {
  82.         lo_fillin_text_info(context, state);
  83.  
  84.         font_height = state->text_info.ascent + state->text_info.descent;
  85.     }
  86.  
  87.     return font_height;
  88. }
  89.  
  90. PRIVATE double
  91. lo_get_css_scaling_factor_percentage(MWContext * context)
  92. {
  93.     if(context && context->fontScalingPercentage > 0.0)
  94.         return(context->fontScalingPercentage);
  95.     else 
  96.         return(1.0);
  97. }
  98.  
  99. /* converts any unit into pixels 
  100.  * except fonts get converted to points
  101.  */
  102. void
  103. LO_AdjustSSUnits(SS_Number *number, char *style_type, MWContext *context, lo_DocState *state)
  104. {
  105.     enum unit_type { EMS, EXS, PTS, PXS, PCS, REL, PER, INS, CMS, MMS };
  106.     enum unit_type units;
  107.     double scaler;
  108.     double pixels_per_point=1.0;
  109.  
  110.     if(!number || !number->units || !style_type || !state || !context)
  111.         return;
  112.  
  113.     XP_ASSERT(FEUNITS_X(1, context) == FEUNITS_Y(1, context));
  114.  
  115. #if (defined XP_WIN || defined XP_UNIX)
  116.     /* mac has 72 dots per inch */
  117.     pixels_per_point = context->YpixelsPerPoint;
  118. #endif
  119.  
  120. #ifdef XP_WIN
  121.     /* multiply ppp by the inverse of th LP to DP decreaser
  122.      * to obtain DP to LP
  123.      */
  124.     if(context->type == MWContextPrint) 
  125.         pixels_per_point *= 1000000.0/(double)FE_LPtoDPoint(context, 1000000);
  126. #endif /* WP_WIN */
  127.  
  128.     scaler = lo_get_css_scaling_factor_percentage(context);
  129.  
  130.     if(!strncasecomp(number->units, "em", 2))
  131.         units = EMS;
  132.     else if(!strncasecomp(number->units, "ex", 2))
  133.         units = EXS;
  134.     else if(!strncasecomp(number->units, "px", 2))
  135.         units = PXS;
  136.     else if(!strncasecomp(number->units, "pt", 2))
  137.         units = PTS;
  138.     else if(!strncasecomp(number->units, "pc", 2))
  139.         units = PCS;
  140.     else if(!strncasecomp(number->units, "in", 2))
  141.         units = INS;
  142.     else if(!strncasecomp(number->units, "cm", 2))
  143.         units = CMS;
  144.     else if(!strncasecomp(number->units, "mm", 2))
  145.         units = MMS;
  146.     else if(!XP_STRCMP(number->units, "%"))
  147.         units = PER;
  148.     else if(!*number->units)
  149.         units = REL;
  150.     else
  151.         units = PXS;
  152.  
  153.     if(units == PXS)
  154.     {
  155.         /* if going to a printer, adjust the pixels
  156.          * to look like there is 120 pixels per inch
  157.          * we will undo this for pixels below
  158.          * because layout does this too
  159.          */
  160.         number->value = FEUNITS_X(number->value, context);
  161.  
  162.                 /* No - we don't scale pixel values.  Pixels is pixels. */
  163.         /* number->value *= scaler; */
  164.  
  165.     }
  166.     else if(units == EMS || units == EXS)
  167.     {
  168.         int32 font_height = lo_get_font_height(context, state);
  169.  
  170.         if(units == EMS)
  171.             number->value *= font_height;
  172.         else 
  173.             number->value *= font_height/2;
  174.     }
  175.     else if(units == PER)
  176.     {
  177.         /* percentage values depend on the type */
  178.         if(!strcasecomp(style_type, LINE_HEIGHT_STYLE)
  179.            || !strcasecomp(style_type, FONTSIZE_STYLE))
  180.         {
  181.             /* line height is a percentage of the current font
  182.              * just like ems
  183.              */
  184.             int32 font_height = lo_get_font_height(context, state);
  185.  
  186.             number->value *= ((double)font_height)/100;
  187.         }
  188.         else if(!strcasecomp(style_type, HEIGHT_STYLE))
  189.         {
  190.             int32 parent_layer_height = lo_GetEnclosingLayerHeight(state);
  191.             number->value = ((number->value*parent_layer_height))/100;
  192.         }
  193.         else if(!strcasecomp(style_type, LAYER_WIDTH_STYLE))
  194.         {
  195.             int32 parent_layer_width = lo_GetEnclosingLayerWidth(state);
  196.             number->value = ((number->value*parent_layer_width))/100;
  197.         }
  198.         else 
  199.         {
  200.             /* all other percentage values are relative to the width */
  201.             if(!state->width)
  202.                 number->value *= state->win_width/100; 
  203.             else
  204.                 number->value *= state->width/100; 
  205.         }
  206.     }
  207.     else if(units == REL)
  208.     {
  209.         /* relative values depend on the type */
  210.         if(!strcasecomp(style_type, LINE_HEIGHT_STYLE))
  211.         {
  212.             /* line height is a percentage of the current font
  213.              * just like ems
  214.              */
  215.             int32 font_height = lo_get_font_height(context, state);
  216.  
  217.             number->value *= font_height;
  218.         }
  219.         else
  220.         {
  221.             /* all other relative units default to pixels */
  222.             /* scale them as well since they are pixel units */
  223.             number->value = FEUNITS_X(number->value, context);
  224.             number->value *= scaler;
  225.         }
  226.     }
  227.     else if(units == PTS)
  228.     {
  229.         number->value *= pixels_per_point; /* now it's in pixels */
  230.         number->value *= scaler;
  231.     }
  232.     else if(units == PCS)
  233.     {
  234.         /* 1 PCS == 12 PTS */
  235.         number->value = number->value*12.0; /* now its in points */
  236.         number->value *= pixels_per_point; /* now it's in pixels */
  237.         number->value *= scaler;
  238.     }
  239.     else if(units == INS)
  240.     {
  241.         /* 1pt == 1/72in */
  242.         number->value *= 72.0; /* now its in points */
  243.         number->value *= pixels_per_point; /* now it's in pixels */
  244.         number->value *= scaler;
  245.     }
  246.     else if(units == CMS)
  247.     {
  248.         /* 1in == 2.54cm  and 1in == 72 pts */
  249.         number->value *= 72.0 / 2.54; /* now its in points */
  250.         number->value *= pixels_per_point; /* now it's in pixels */
  251.         number->value *= scaler;
  252.     }
  253.     else if(units == MMS)
  254.     {
  255.         /* 1in == 25.4mm  and 1in == 72 pts */
  256.         number->value *= 72.0 / 25.4; /* now its in points */
  257.         number->value *= pixels_per_point; /* now it's in pixels */
  258.         number->value *= scaler;
  259.     }
  260.     else
  261.     {
  262.         XP_ASSERT(0);
  263.     }
  264.  
  265.     /* the number has been converted to pixels now */
  266.  
  267.     XP_FREE(number->units);
  268.     if(!strcasecomp(style_type, FONTSIZE_STYLE))
  269.     {
  270.         /* fonts are expressed in points not pixels
  271.          * convert to (or back) from pixels
  272.          */
  273.         number->value /= pixels_per_point;
  274.         number->units = XP_STRDUP("pts");
  275.     }
  276.     else
  277.     {
  278.         /* all non-font values are now scaled to
  279.          * the FEUNITS coordinate system.  Since
  280.          * layout will automaticly try to scale
  281.          * these values up to FEUNITS we need to
  282.          * down scale the values so that they
  283.          * are not too large.
  284.          *
  285.          * @@@ bug always X scaled not Y scaled
  286.          */
  287.         number->value = number->value/(double)FEUNITS_X(1, context);
  288.         number->units = XP_STRDUP("px");
  289.     }
  290.     
  291.     return; /* conversion complete */
  292.  
  293. }
  294. /* returns TRUE if the display: none property
  295.  * is set
  296.  */
  297. XP_Bool
  298. LO_CheckForContentHiding(lo_DocState *state)
  299. {
  300.     StyleStruct *style_struct;
  301.     char *prop;
  302.     XP_Bool hide_content = FALSE;
  303.  
  304.     if(!state || !state->top_state || !state->top_state->style_stack)
  305.         return FALSE;
  306.  
  307.     /* check the current stack to see if we are currently hiding text */
  308.     style_struct = STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0);
  309.  
  310.     if(style_struct)
  311.     {
  312.         prop = STYLESTRUCT_GetString(style_struct, DISPLAY_STYLE);
  313.  
  314.         if(prop)
  315.         {
  316.             if(!XP_STRCMP(prop, NONE_STYLE))
  317.                 hide_content = TRUE;
  318.     
  319.             XP_FREE(prop);
  320.         }
  321.     }
  322.     
  323.     return hide_content;
  324. }
  325.  
  326. #define SS_ENABLED_PREF "browser.enable_style_sheets"
  327. Bool lo_style_sheets_enabled = TRUE;
  328.  
  329. int PR_CALLBACK
  330. lo_ss_enabled_changed(const char *domain, void *closure)
  331. {
  332.     Bool rv;
  333.  
  334.     /* the scaling factor should increase things by 10% */
  335.     if(!PREF_GetBoolPref(SS_ENABLED_PREF, &rv))
  336.         lo_style_sheets_enabled = rv;
  337.     return 0;
  338. }
  339.  
  340. XP_Bool
  341. LO_StyleSheetsEnabled(MWContext *context)
  342. {
  343.     static XP_Bool first_time = TRUE;
  344.  
  345.     if(EDT_IS_EDITOR(context))
  346.     return FALSE;
  347.  
  348.     if(first_time)
  349.     {
  350.         Bool    rv;
  351.         /* the scaling factor should increase things by 10% */
  352.         if(!PREF_GetBoolPref(SS_ENABLED_PREF, &rv))
  353.            lo_style_sheets_enabled = rv;
  354.  
  355.         PREF_RegisterCallback(SS_ENABLED_PREF, lo_ss_enabled_changed, NULL);
  356.  
  357.     first_time = FALSE;
  358.     }
  359.  
  360.     return(lo_style_sheets_enabled);
  361. }
  362.  
  363. PA_Tag *
  364. LO_CreateStyleSheetDummyTag(PA_Tag *old_tag)
  365. {
  366.     PA_Tag *new_tag = PA_CloneMDLTag(old_tag);
  367.     if(new_tag)
  368.     {
  369.         new_tag->type = P_UNKNOWN;
  370.         /* print the tag name into an attribute to save it */
  371.         XP_FREE(new_tag->data);
  372.         new_tag->data = (PA_Block)PR_smprintf(NS_STYLE_NAME_ATTR"=\"%s\" %s", 
  373.                                         pa_PrintTagToken(old_tag->type),
  374.                                         old_tag->data);
  375.         new_tag->data_len = XP_STRLEN((char*)new_tag->data);
  376.     }
  377.  
  378.     return(new_tag);
  379. }
  380.  
  381. PUBLIC PushTagStatus
  382. LO_PushTagOnStyleStack(MWContext *context, lo_DocState *state, PA_Tag *tag)
  383. {
  384.     char *class_name, *id_name, *style_value, *new_name;
  385.     char *tag_name=NULL, *tag_name_attr = NULL;
  386.     PushTagStatus rv;
  387.     XP_Bool style_sheets_prev_encountered;
  388.     char *buf;
  389.  
  390.     char *tableParams[] = 
  391.     {
  392.         NS_STYLE_NAME_ATTR,
  393.         PARAM_CLASS,
  394.         PARAM_ID,
  395.         PARAM_STYLE,
  396.     };
  397.  
  398.     char *temp_tag_name;
  399.     char *tableParamValues[4];
  400.     const int sizeOfParamsTable = 4;
  401.     int k;
  402.  
  403.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  404.     int16 win_csid = INTL_GetCSIWinCSID(c);
  405.  
  406.     if(!LO_StyleSheetsEnabled(context))
  407.         return PUSH_TAG_ERROR;
  408.  
  409.     if(tag->type == P_TEXT || !state->top_state || !state->top_state->style_stack)
  410.         return PUSH_TAG_ERROR;
  411.  
  412.     /*
  413.      * This is a performance enhancement
  414.      * We put this test here to keep from calling PA_FetchRequestedNameValues so many times
  415.      * as PA_FetchRequestedNameValues is a very time expensive routine
  416.      */
  417.     style_sheets_prev_encountered = 
  418.                STYLESTACK_IsSaveOn(state->top_state->style_stack);
  419.     if( !style_sheets_prev_encountered )
  420.     {
  421.         PA_LOCK(buf, char *, tag->data);
  422.         if( (!XP_STRCASESTR( buf, NS_STYLE_NAME_ATTR) && !XP_STRCASESTR( buf, PARAM_STYLE)) )
  423.         {
  424.             PA_UNLOCK(tag->data);
  425.             return PUSH_TAG_ERROR;
  426.         }
  427.         PA_UNLOCK(tag->data);        
  428.     }
  429.  
  430.     /*
  431.      * This is a performance enhancement
  432.      * We put this test here to keep from calling PA_FetchRequestedNameValues so many times
  433.      * as PA_FetchRequestedNameValues is a very time expensive rountine
  434.      */
  435.     if( !style_sheets_prev_encountered || !state->in_relayout )
  436.     {
  437.         /* we only want ot fetch a hidden tag name from a secret attribute stored
  438.          * in the state->subdoc_tags list
  439.          * if state->in_relayout and style_sheets_prev_encountered  
  440.          */
  441.         /* normally we want to ignore uknown tags
  442.          * but we need to pay some special attention
  443.          * to these tags in the relayout state
  444.          */
  445.         if(tag->type == P_UNKNOWN )
  446.         {
  447.             rv = PUSH_TAG_ERROR;
  448.             return(rv);
  449.         }
  450.             
  451.     }
  452.  
  453.     for( k = 0; k < sizeOfParamsTable; k++ )
  454.         tableParamValues[k] = NULL;
  455.  
  456.     PA_FetchRequestedNameValues( tag, tableParams, sizeOfParamsTable, tableParamValues, win_csid );  
  457.  
  458.     tag_name_attr = tableParamValues[0];
  459.     tag_name = tag_name_attr;
  460.     class_name = tableParamValues[1];
  461.     id_name = tableParamValues[2];
  462.     style_value = tableParamValues[3];
  463.  
  464.  
  465.     /* normally we want to ignore uknown tags
  466.      * but we need to pay some special attention
  467.      * to these tags in the relayout state
  468.      */
  469.     if(tag->type == P_UNKNOWN && !tag_name_attr)
  470.     {
  471.         rv = PUSH_TAG_ERROR;
  472.         XP_FREEIF(style_value);
  473.         XP_FREEIF(tag_name_attr);
  474.         XP_FREEIF(class_name);
  475.         XP_FREEIF(id_name);
  476.         return(rv);
  477.     }
  478.  
  479.     /*
  480.      *style_value freed in lo_ProcessStyleAttribute
  481.      */
  482.     if(lo_ProcessStyleAttribute(context, state, tag, style_value))
  483.     {
  484.         /* enable the tag stack */
  485.             STYLESTACK_SetSaveOn(state->top_state->style_stack, TRUE);
  486.         rv = PUSH_TAG_BLOCKED;
  487.         XP_FREEIF(tag_name_attr);
  488.         XP_FREEIF(class_name);
  489.         XP_FREEIF(id_name);
  490.         return(rv);
  491.     }
  492.  
  493.     
  494.     if(id_name)
  495.     {
  496.         new_name = CSS_ConvertToJSCompatibleName(id_name, FALSE);
  497.         if(new_name)
  498.         {
  499.             XP_FREE(id_name);
  500.             id_name = new_name;
  501.         }
  502.     }
  503.     else
  504.         id_name = PR_smprintf(NSIMPLICITID"%ld", state->top_state->tag_count);
  505.  
  506.     if(class_name)
  507.     {
  508.         new_name = CSS_ConvertToJSCompatibleName(class_name, FALSE);
  509.         if(new_name)
  510.         {
  511.             XP_FREE(class_name);
  512.             class_name = new_name;
  513.         }
  514.     }
  515.  
  516.     if(!tag_name)
  517.     {
  518.         temp_tag_name = (char*)pa_PrintTagToken((int32)tag->type);
  519.         tag_name = XP_STRDUP( temp_tag_name );
  520.     }
  521.  
  522.     /* call into the style stack class */
  523.     rv = STYLESTACK_PushTag(state->top_state->style_stack, 
  524.                        tag_name, 
  525.                        class_name, 
  526.                        id_name);
  527.  
  528.     return(rv);
  529. }
  530.  
  531. /* look for implicit tag pops.  For instance the close of a TR tag
  532.  * implicitly pops all TD tags and any other open tags
  533.  */
  534. PUBLIC XP_Bool
  535. LO_ImplicitPop(MWContext *context, lo_DocState **state, PA_Tag *tag)
  536. {
  537.  
  538.     switch(tag->type) 
  539.     {
  540.         case P_LIST_ITEM:
  541.             /* NOTE: there should be no end LI */
  542.             if(tag->is_end)
  543.                 return FALSE;
  544.  
  545.             LO_PopAllTagsAbove(context, 
  546.                                state, 
  547.                                P_LIST_ITEM,
  548.                                P_LIST_ITEM,
  549.                             P_NUM_LIST,
  550.                             P_UNUM_LIST);
  551.             return TRUE;
  552.  
  553.         case P_TABLE_DATA:
  554.             LO_PopAllTagsAbove(context, 
  555.                                state, 
  556.                                P_TABLE_DATA,
  557.                                P_TABLE_DATA,
  558.                             P_TABLE_ROW,
  559.                             P_TABLE);
  560.             return TRUE;
  561.             
  562.         case P_TABLE_ROW:
  563.             LO_PopAllTagsAbove(context, 
  564.                                state, 
  565.                                P_TABLE_ROW,
  566.                             P_TABLE_ROW,
  567.                             P_TABLE,
  568.                             P_UNKNOWN);
  569.             return TRUE;
  570.  
  571.         case P_TABLE:
  572.             /* table begins don't implicitly close tables */
  573.             if(tag->is_end)
  574.                 LO_PopAllTagsAbove(context, 
  575.                                    state, 
  576.                                    P_TABLE,
  577.                                    P_TABLE,
  578.                                 P_UNKNOWN,
  579.                                 P_UNKNOWN);
  580.             return TRUE;
  581.  
  582.         default:
  583.             return FALSE;
  584.     }
  585.  
  586. }
  587.  
  588. PUBLIC void
  589. LO_PopStyleTagByIndex(MWContext *context, lo_DocState **state, 
  590.                       TagType tag_type, int32 index)
  591.  {
  592.     StyleStruct * top_style;
  593.     char *property, *page_break_property;
  594.     SS_Number *bottom_margin; 
  595.     SS_Number *bottom_padding; 
  596.     SS_Number *pop_table;
  597.  
  598.     if(!(*state) || !context || !(*state)->top_state->style_stack || index < 0)
  599.         return;
  600.  
  601.     top_style = STYLESTACK_GetStyleByIndex((*state)->top_state->style_stack,index);
  602.  
  603.     if(!top_style)
  604.         return;
  605.  
  606. #ifdef DEBUG
  607.     {
  608.         TagStruct * stag = STYLESTACK_GetTagByIndex((*state)->top_state->style_stack, 0);
  609.         stag = NULL;  /* set breakpoint here for viewing */
  610.     }
  611. #endif
  612.  
  613.     page_break_property = STYLESTRUCT_GetString(top_style, PAGE_BREAK_AFTER_STYLE);
  614.     if (page_break_property)
  615.     {
  616.         if(!strcasecomp(page_break_property, "auto"))
  617.         {
  618.             /* not currently supported */
  619.         }
  620.         else if(!strcasecomp(page_break_property, "always"))
  621.         {
  622.             /* not currently supported */
  623.         }
  624.         else if(!strcasecomp(page_break_property, "left"))
  625.         {
  626.             /* not currently supported */
  627.         }
  628.         else if(!strcasecomp(page_break_property, "right"))
  629.         {
  630.             /* not currently supported */
  631.         }
  632.         XP_FREE(page_break_property);
  633.     }
  634.  
  635.     /* calculate the bottom margin here since we need the original font
  636.      * information before closing the table, but don't apply it until
  637.      * after the table is closed
  638.      */
  639.     bottom_margin = STYLESTRUCT_GetNumber(top_style, BOTTOMMARGIN_STYLE);
  640.     LO_AdjustSSUnits(bottom_margin, BOTTOMMARGIN_STYLE, context, *state);
  641.  
  642.     if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_PRE)) != NULL)
  643.     {
  644.         (*state)->preformatted = PRE_TEXT_NO;
  645.         FE_EndPreSection(context);
  646.         XP_FREE(property);
  647.     }
  648.     else if((property = STYLESTRUCT_GetString(top_style, 
  649.                                               STYLE_NEED_TO_RESET_PRE)) != NULL)
  650.     {
  651.         /* @@@ hack
  652.          * use this stack to reset pre if we exited from it
  653.          * via a whiteSpace: normal directive
  654.          */
  655.         (*state)->preformatted = PRE_TEXT_YES;
  656.         FE_BeginPreSection(context);
  657.         XP_FREE(property);
  658.     }
  659.  
  660.     /* pop any necessary stacks */
  661.     if((pop_table = STYLESTRUCT_GetNumber(top_style, STYLE_NEED_TO_POP_TABLE)) != NULL)
  662.     {
  663.         lo_TopState *top_state;
  664.         int32 doc_id;
  665.  
  666.         if(pop_table->value)
  667.         {
  668.             /* unset the property to prevent reentrancy from popping the
  669.              * table twice 
  670.              */
  671.             STYLESTRUCT_SetString(top_style, 
  672.                                   STYLE_NEED_TO_POP_TABLE, 
  673.                                   "0", 
  674.                                   MAX_STYLESTRUCT_PRIORITY);
  675.             lo_CloseTable(context, *state);
  676.  
  677.             /* get the new current state */
  678.             doc_id = XP_DOCID(context);
  679.             top_state = lo_FetchTopState(doc_id);
  680.             *state = lo_TopSubState(top_state);
  681.         }
  682.  
  683.         STYLESTRUCT_FreeSSNumber(top_style, pop_table);
  684.     }
  685.     else
  686.     {
  687.  
  688.         /* add bottom padding */
  689.         bottom_padding = STYLESTRUCT_GetNumber(top_style, BOTTOMPADDING_STYLE);
  690.         LO_AdjustSSUnits(bottom_padding, BOTTOMPADDING_STYLE, context, *state);
  691.         if(bottom_padding && bottom_padding->value > 0)
  692.         {
  693.             int32 move_size = FEUNITS_Y((int32)bottom_padding->value, context);
  694.             lo_SetSoftLineBreakState(context, *state, FALSE, 1);
  695.             (*state)->y += move_size;
  696.         }
  697.         STYLESTRUCT_FreeSSNumber(top_style, bottom_padding);
  698.     }
  699.         
  700.     property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_ALIGNMENT);
  701.     if(property)
  702.     {
  703.         lo_AlignStack *lptr;
  704.         /* flush the line to get the alignment correct */
  705.         lo_SetSoftLineBreakState(context, *state, FALSE, 1);
  706.         lptr = lo_PopAlignment(*state);
  707.            if (lptr != NULL)
  708.                XP_DELETE(lptr);
  709.         XP_FREE(property);
  710.     }
  711.  
  712.     /* pop the last List */
  713.     if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_MARGINS)) != NULL)
  714.     {
  715.         lo_ListStack *lptr;
  716.  
  717.         XP_FREE(property);
  718.  
  719.         if((*state)->list_stack)
  720.         {
  721.             lptr = lo_PopList(*state, NULL);
  722.             if (lptr != NULL)
  723.                 XP_DELETE(lptr);
  724.             (*state)->left_margin = (*state)->list_stack->old_left_margin;
  725.             (*state)->right_margin = (*state)->list_stack->old_right_margin;
  726.  
  727.             lo_SetSoftLineBreakState(context, *state, FALSE, 1);
  728.             (*state)->x = (*state)->left_margin;
  729.         }     
  730.     }
  731.  
  732.     if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_LIST)) != NULL)
  733.     {
  734.         XP_FREE(property);
  735.  
  736.         lo_TeardownList(context, *state, NULL);
  737.     }
  738.  
  739.     /* apply bottom margins */
  740.     if(bottom_margin && bottom_margin->value > 0)
  741.     {
  742.         int32 move_size = FEUNITS_Y((int32)bottom_margin->value, context);
  743.         lo_SetSoftLineBreakState(context, *state, FALSE, 1);
  744.         (*state)->y += move_size;
  745.     }
  746.     STYLESTRUCT_FreeSSNumber(top_style, bottom_margin);
  747.  
  748.     property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_LINE_HEIGHT);
  749.     if(property)
  750.     {
  751.         lo_LineHeightStack *lptr;
  752.         lptr = lo_PopLineHeight(*state);
  753.            if (lptr != NULL)
  754.                XP_DELETE(lptr);
  755.         XP_FREE(property);
  756.     }
  757.  
  758.     /* pop layers last since they get pushed first */
  759.     property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_LAYER);
  760.     if(property)
  761.     {
  762.         lo_EndLayer(context, *state, PR_TRUE);
  763.     }
  764.     
  765.     if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_FONT)) != NULL)
  766.     {
  767.         XP_FREE(property);
  768.         lo_PopFont(*state, tag_type);
  769.     }
  770.  
  771.     if((property = STYLESTRUCT_GetString(top_style, 
  772.                                         STYLE_NEED_TO_POP_CONTENT_HIDING)) != NULL)
  773.     {
  774.         XP_FREE(property);
  775.         (*state)->hide_content = FALSE;
  776.     }
  777.  
  778.     STYLESTACK_PopTagByIndex((*state)->top_state->style_stack,(char*)pa_PrintTagToken((int32)tag_type), index);
  779.  
  780. }
  781.  
  782. PUBLIC void
  783. LO_PopStyleTag(MWContext *context, lo_DocState **state, PA_Tag *tag)
  784. {
  785.     /* look for tags that need to be implicitly pop'd */
  786.     if(!LO_ImplicitPop(context, state, tag))
  787.         LO_PopStyleTagByIndex(context, state, tag->type, 0);
  788.  
  789. }
  790.  
  791. PRIVATE int 
  792. compare_tag_type_and_name(TagType tag_type, char *tag_name)
  793. {
  794.     return strcasecomp((char *)pa_PrintTagToken((int32)tag_type), tag_name);
  795. }
  796.  
  797. /* pops all the tags in the stack above the type specified.
  798.  *
  799.  * the not_below_this argument if non P_UNKNOWN specifies a tag type to
  800.  * halt the search on.  By default this will search to the
  801.  * bottom of the stack.
  802.  *
  803.  * for instance to pop all tags above TR but not below TABLE
  804.  *  LO_PopAllTagsAbove(context, state, P_TR, P_TABLE, P_UNKNOWN, P_UNKNOWN)
  805.  *
  806.  * This function pops the tag of the specified type. (so TR would NOT still 
  807.  * be on the stack)
  808.  *
  809.  * returns TRUE if tag_type was found and popped.
  810.  * returns FALSE if tag_type not found or error
  811.  */
  812. PUBLIC XP_Bool
  813. LO_PopAllTagsAbove(MWContext *context, 
  814.                    lo_DocState **state,
  815.                    TagType tag_type, 
  816.                    TagType not_below_this,
  817.                    TagType or_this,
  818.                    TagType or_this_either)
  819. {
  820.     TagStruct * top_tag;
  821.     int32 index = 0;
  822.  
  823.     if(!(*state) || !context || !(*state)->top_state->style_stack || index < 0)
  824.         return FALSE;
  825.  
  826.     top_tag = STYLESTACK_GetTagByIndex((*state)->top_state->style_stack,index);
  827.  
  828.     while(top_tag)
  829.     {
  830.         if(!compare_tag_type_and_name(tag_type, top_tag->name))
  831.         {
  832.             /* found it */
  833.  
  834.             /* pop it and all tags above in stack order */
  835.             for(; index > -1; index--)
  836.                 LO_PopStyleTagByIndex(context, state, tag_type, 0);
  837.                 
  838.             return TRUE;
  839.         }
  840.  
  841.         if(   (not_below_this != P_UNKNOWN
  842.                && !compare_tag_type_and_name(not_below_this, top_tag->name))
  843.            || (or_this != P_UNKNOWN
  844.                && !compare_tag_type_and_name(or_this, top_tag->name))
  845.            || (or_this_either != P_UNKNOWN
  846.                && !compare_tag_type_and_name(or_this_either, top_tag->name)))
  847.             return FALSE; /* not found */
  848.  
  849.         index++;
  850.         top_tag = STYLESTACK_GetTagByIndex((*state)->top_state->style_stack, index);
  851.     }
  852.  
  853.     return FALSE;
  854. }
  855.  
  856. PRIVATE int32
  857. lo_get_width_or_height_from_style_sheet(MWContext *context, 
  858.                     lo_DocState *state, 
  859.                     int type)
  860. {
  861.     StyleStruct *top_style;
  862.     SS_Number *ss_val;
  863.     int32 val=0;
  864.  
  865.     /* get the most current style struct */
  866.     if ( ! state->top_state->style_stack )
  867.         return 0;
  868.     top_style = STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0);
  869.  
  870.     if(!top_style)
  871.         return 0;
  872.  
  873.     /* get the property */
  874.     if(type == _STYLE_GET_WIDTH)
  875.     {
  876.         ss_val = STYLESTRUCT_GetNumber(top_style, WIDTH_STYLE);
  877.     }
  878.     else if(type == _STYLE_GET_HEIGHT)
  879.     {
  880.         ss_val = STYLESTRUCT_GetNumber(top_style, HEIGHT_STYLE);
  881.     }
  882.     else
  883.     {
  884.         XP_ASSERT(0);
  885.         return 0;
  886.     }
  887.  
  888.     if(ss_val)
  889.     {
  890.         /* do unit conversions here */
  891.         LO_AdjustSSUnits(ss_val, WIDTH_STYLE, context, state);
  892.  
  893.         /* convert to fe units */
  894.         if(type == _STYLE_GET_WIDTH)
  895.             val = FEUNITS_X((int32)ss_val->value, context);
  896.         else if(type == _STYLE_GET_HEIGHT)
  897.             val = FEUNITS_Y((int32)ss_val->value, context);
  898.         
  899.         if(val < 1)
  900.             val = 1;
  901.  
  902.         STYLESTRUCT_FreeSSNumber(top_style, ss_val);
  903.         return val;
  904.     }
  905.  
  906.     return 0;
  907. }
  908.  
  909. PUBLIC int32
  910. LO_GetWidthFromStyleSheet(MWContext *context, lo_DocState *state)
  911. {
  912.     return lo_get_width_or_height_from_style_sheet(context, 
  913.                                                    state, 
  914.                                                    _STYLE_GET_WIDTH);
  915. }
  916.  
  917. PUBLIC int32
  918. LO_GetHeightFromStyleSheet(MWContext *context, lo_DocState *state)
  919. {
  920.     return lo_get_width_or_height_from_style_sheet(context, 
  921.                                                    state, 
  922.                                                    _STYLE_GET_HEIGHT);
  923. }
  924.  
  925. #if 0
  926. static XP_Bool
  927. IsJSS(MWContext *context, PA_Tag *tag)
  928. {
  929.     PA_Block    buff;
  930.     char       *str;
  931.     XP_Bool     bResult = FALSE;
  932.  
  933.     /* See if it's JavaScript style sheets or something else like CSS */
  934.     buff = lo_FetchParamValue(context, tag, PARAM_TYPE);
  935.     
  936.     if (buff != NULL) {
  937.         PA_LOCK(str, char *, buff);
  938.  
  939.         if (XP_STRCASECMP(str, "text/javascript") == 0)
  940.             bResult = TRUE;
  941.  
  942.             PA_UNLOCK(buff);
  943.             PA_FREE(buff);
  944.         }
  945.  
  946.     return bResult;
  947. }
  948. #endif /* 0 */
  949.  
  950. /* This code is just a wrapper around lo_ProcessScriptTag() */
  951. void
  952. lo_ProcessStyleTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  953. {
  954.     if(state && state->top_state && state->top_state->style_stack)
  955.     {
  956.         STYLESTACK_SetSaveOn(state->top_state->style_stack, TRUE);        
  957.     }
  958.  
  959.     lo_ProcessScriptTag(context, state, tag, NULL);
  960. }
  961.