gecko-dev/lib/layout/laystyle.c
shaver%netscape.com 453cc779ce Use ACTIVE_NODE now rather than CURRENT_NODE, and include lm_dom.h everywhere
to make that possible.
Move LM_ReflectNode call to laytags.c back-end from layout.c front-end (thank
you, Uncle Brendan).
Correct FIND_LAST_ELEMENT to handle newly-ended doc_states.
1998-10-09 00:46:05 +00:00

1002 lines
24 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* STYLE tag support.
*/
#include "xp.h"
#include "libmocha.h"
#include "lo_ele.h"
#include "pa_parse.h"
#include "pa_tags.h"
#include "layout.h"
#include "laylayer.h"
#include "laystyle.h"
#include "prefapi.h"
#include "css.h"
#include "intl_csi.h"
#ifdef DOM
#include "domstyle.h"
#include "lm_dom.h"
#endif
void
LO_SetStyleObjectRefs(MWContext *context, void *tags, void *classes, void *ids)
{
lo_TopState *top_state;
LO_LockLayout();
top_state = lo_FetchTopState(XP_DOCID(context));
if (top_state && top_state->style_stack) {
SML_SetObjectRefs(top_state->style_stack, tags, classes, ids);
}
LO_UnlockLayout();
}
#define _STYLE_GET_WIDTH 0
#define _STYLE_GET_HEIGHT 1
char *
lo_ParseStyleSheetURL(char *url_string)
{
if(!url_string)
return NULL;
/* look for url() around the url and strip it off */
if(!strncasecomp(url_string, "url(", 4))
{
int end;
url_string += 4; /* skip past "url(" */
end = XP_STRLEN(url_string)-1;
/* strip the ")" */
if(url_string[end] == ')')
url_string[end] = '\0';
}
return url_string;
}
PRIVATE int32
lo_get_font_height(MWContext *context, lo_DocState *state)
{
int32 font_height = state->text_info.ascent +
state->text_info.descent;
if ((font_height <= 0)
#ifndef DOM
&&(state->font_stack != NULL)&&
(state->font_stack->text_attr != NULL)
#endif
)
{
lo_fillin_text_info(context, state);
font_height = state->text_info.ascent + state->text_info.descent;
}
return font_height;
}
PRIVATE double
lo_get_css_scaling_factor_percentage(MWContext * context)
{
if(context && context->fontScalingPercentage > 0.0)
return(context->fontScalingPercentage);
else
return(1.0);
}
/* converts any unit into pixels
* except fonts get converted to points
*/
void
LO_AdjustSSUnits(SS_Number *number, char *style_type, MWContext *context, lo_DocState *state)
{
enum unit_type { EMS, EXS, PTS, PXS, PCS, REL, PER, INS, CMS, MMS };
enum unit_type units;
double scaler;
double pixels_per_point=1.0;
if(!number || !number->units || !style_type || !state || !context)
return;
XP_ASSERT(FEUNITS_X(1, context) == FEUNITS_Y(1, context));
#if (defined XP_WIN || defined XP_UNIX)
/* mac has 72 dots per inch */
pixels_per_point = context->YpixelsPerPoint;
#endif
#ifdef XP_WIN
/* multiply ppp by the inverse of th LP to DP decreaser
* to obtain DP to LP
*/
if(context->type == MWContextPrint)
pixels_per_point *= 1000000.0/(double)FE_LPtoDPoint(context, 1000000);
#endif /* WP_WIN */
scaler = lo_get_css_scaling_factor_percentage(context);
if(!strncasecomp(number->units, "em", 2))
units = EMS;
else if(!strncasecomp(number->units, "ex", 2))
units = EXS;
else if(!strncasecomp(number->units, "px", 2))
units = PXS;
else if(!strncasecomp(number->units, "pt", 2))
units = PTS;
else if(!strncasecomp(number->units, "pc", 2))
units = PCS;
else if(!strncasecomp(number->units, "in", 2))
units = INS;
else if(!strncasecomp(number->units, "cm", 2))
units = CMS;
else if(!strncasecomp(number->units, "mm", 2))
units = MMS;
else if(!XP_STRCMP(number->units, "%"))
units = PER;
else if(!*number->units)
units = REL;
else
units = PXS;
if(units == PXS)
{
/* if going to a printer, adjust the pixels
* to look like there is 120 pixels per inch
* we will undo this for pixels below
* because layout does this too
*/
number->value = FEUNITS_X(number->value, context);
/* No - we don't scale pixel values. Pixels is pixels. */
/* number->value *= scaler; */
}
else if(units == EMS || units == EXS)
{
int32 font_height = lo_get_font_height(context, state);
if(units == EMS)
number->value *= font_height;
else
number->value *= font_height/2;
}
else if(units == PER)
{
/* percentage values depend on the type */
if(!strcasecomp(style_type, LINE_HEIGHT_STYLE)
|| !strcasecomp(style_type, FONTSIZE_STYLE))
{
/* line height is a percentage of the current font
* just like ems
*/
int32 font_height = lo_get_font_height(context, state);
number->value *= ((double)font_height)/100;
}
else if(!strcasecomp(style_type, HEIGHT_STYLE))
{
int32 parent_layer_height = lo_GetEnclosingLayerHeight(state);
number->value = ((number->value*parent_layer_height))/100;
}
else if(!strcasecomp(style_type, LAYER_WIDTH_STYLE))
{
int32 parent_layer_width = lo_GetEnclosingLayerWidth(state);
number->value = ((number->value*parent_layer_width))/100;
}
else
{
/* all other percentage values are relative to the width */
if(!state->width)
number->value *= state->win_width/100;
else
number->value *= state->width/100;
}
}
else if(units == REL)
{
/* relative values depend on the type */
if(!strcasecomp(style_type, LINE_HEIGHT_STYLE))
{
/* line height is a percentage of the current font
* just like ems
*/
int32 font_height = lo_get_font_height(context, state);
number->value *= font_height;
}
else
{
/* all other relative units default to pixels */
/* scale them as well since they are pixel units */
number->value = FEUNITS_X(number->value, context);
number->value *= scaler;
}
}
else if(units == PTS)
{
number->value *= pixels_per_point; /* now it's in pixels */
number->value *= scaler;
}
else if(units == PCS)
{
/* 1 PCS == 12 PTS */
number->value = number->value*12.0; /* now its in points */
number->value *= pixels_per_point; /* now it's in pixels */
number->value *= scaler;
}
else if(units == INS)
{
/* 1pt == 1/72in */
number->value *= 72.0; /* now its in points */
number->value *= pixels_per_point; /* now it's in pixels */
number->value *= scaler;
}
else if(units == CMS)
{
/* 1in == 2.54cm and 1in == 72 pts */
number->value *= 72.0 / 2.54; /* now its in points */
number->value *= pixels_per_point; /* now it's in pixels */
number->value *= scaler;
}
else if(units == MMS)
{
/* 1in == 25.4mm and 1in == 72 pts */
number->value *= 72.0 / 25.4; /* now its in points */
number->value *= pixels_per_point; /* now it's in pixels */
number->value *= scaler;
}
else
{
XP_ASSERT(0);
}
/* the number has been converted to pixels now */
XP_FREE(number->units);
if(!strcasecomp(style_type, FONTSIZE_STYLE))
{
/* fonts are expressed in points not pixels
* convert to (or back) from pixels
*/
number->value /= pixels_per_point;
number->units = XP_STRDUP("pts");
}
else
{
/* all non-font values are now scaled to
* the FEUNITS coordinate system. Since
* layout will automaticly try to scale
* these values up to FEUNITS we need to
* down scale the values so that they
* are not too large.
*
* @@@ bug always X scaled not Y scaled
*/
number->value = number->value/(double)FEUNITS_X(1, context);
number->units = XP_STRDUP("px");
}
return; /* conversion complete */
}
#ifdef DOM
XP_Bool
LO_CheckForContentHiding(lo_DocState *state, MWContext *context)
{
JSContext *cx = context->mocha_context;
DOM_StyleDatabase *db = state->top_state->style_db;
DOM_Node *node = ACTIVE_NODE(state);
DOM_AttributeEntry *entry;
if (!db || !cx || !node ||
!DOM_StyleGetProperty(cx, db, node, DISPLAY_STYLE, &entry)) {
#ifdef DEBUG_shaver
fprintf(stderr, "not suppressing display\n");
#endif
return FALSE;
}
if (entry && !XP_STRCMP(entry->value, NONE_STYLE)) {
#ifdef DEBUG_shaver
fprintf(stderr, "suppressing display\n");
#endif
return TRUE;
}
#ifdef DEBUG_shaver
fprintf(stderr, "not suppressing display\n");
#endif
return FALSE;
}
#else
/* returns TRUE if the display: none property
* is set
*/
XP_Bool
LO_CheckForContentHiding(lo_DocState *state)
{
StyleStruct *style_struct;
char *prop;
XP_Bool hide_content = FALSE;
if(!state || !state->top_state || !state->top_state->style_stack)
return FALSE;
/* check the current stack to see if we are currently hiding text */
style_struct = STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0);
if(style_struct)
{
prop = STYLESTRUCT_GetString(style_struct, DISPLAY_STYLE);
if(prop)
{
if(!XP_STRCMP(prop, NONE_STYLE))
hide_content = TRUE;
XP_FREE(prop);
}
}
return hide_content;
}
#endif /* DOM */
#define SS_ENABLED_PREF "browser.enable_style_sheets"
Bool lo_style_sheets_enabled = TRUE;
int PR_CALLBACK
lo_ss_enabled_changed(const char *domain, void *closure)
{
Bool rv;
/* the scaling factor should increase things by 10% */
if(!PREF_GetBoolPref(SS_ENABLED_PREF, &rv))
lo_style_sheets_enabled = rv;
return 0;
}
XP_Bool
LO_StyleSheetsEnabled(MWContext *context)
{
static XP_Bool first_time = TRUE;
if(EDT_IS_EDITOR(context))
return FALSE;
if(first_time)
{
Bool rv;
/* the scaling factor should increase things by 10% */
if(!PREF_GetBoolPref(SS_ENABLED_PREF, &rv))
lo_style_sheets_enabled = rv;
PREF_RegisterCallback(SS_ENABLED_PREF, lo_ss_enabled_changed, NULL);
first_time = FALSE;
}
return(lo_style_sheets_enabled);
}
PA_Tag *
LO_CreateStyleSheetDummyTag(PA_Tag *old_tag)
{
PA_Tag *new_tag = PA_CloneMDLTag(old_tag);
if(new_tag)
{
new_tag->type = P_UNKNOWN;
/* print the tag name into an attribute to save it */
XP_FREE(new_tag->data);
new_tag->data = (PA_Block)PR_smprintf(NS_STYLE_NAME_ATTR"=\"%s\" %s",
pa_PrintTagToken(old_tag->type),
old_tag->data);
new_tag->data_len = XP_STRLEN((char*)new_tag->data);
}
return(new_tag);
}
PUBLIC PushTagStatus
LO_PushTagOnStyleStack(MWContext *context, lo_DocState *state, PA_Tag *tag)
{
char *class_name, *id_name, *style_value, *new_name;
char *tag_name=NULL, *tag_name_attr = NULL;
PushTagStatus rv;
XP_Bool style_sheets_prev_encountered;
char *buf;
char *tableParams[] =
{
NS_STYLE_NAME_ATTR,
PARAM_CLASS,
PARAM_ID,
PARAM_STYLE,
};
char *temp_tag_name;
char *tableParamValues[4];
const int sizeOfParamsTable = 4;
int k;
INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
int16 win_csid = INTL_GetCSIWinCSID(c);
if(!LO_StyleSheetsEnabled(context))
return PUSH_TAG_ERROR;
if(tag->type == P_TEXT || !state->top_state || !state->top_state->style_stack)
return PUSH_TAG_ERROR;
/*
* This is a performance enhancement
* We put this test here to keep from calling PA_FetchRequestedNameValues so many times
* as PA_FetchRequestedNameValues is a very time expensive routine
*/
style_sheets_prev_encountered =
STYLESTACK_IsSaveOn(state->top_state->style_stack);
if( !style_sheets_prev_encountered )
{
PA_LOCK(buf, char *, tag->data);
if( (!XP_STRCASESTR( buf, NS_STYLE_NAME_ATTR) && !XP_STRCASESTR( buf, PARAM_STYLE)) )
{
PA_UNLOCK(tag->data);
return PUSH_TAG_ERROR;
}
PA_UNLOCK(tag->data);
}
/*
* This is a performance enhancement
* We put this test here to keep from calling PA_FetchRequestedNameValues so many times
* as PA_FetchRequestedNameValues is a very time expensive rountine
*/
if( !style_sheets_prev_encountered || !state->in_relayout )
{
/* we only want ot fetch a hidden tag name from a secret attribute stored
* in the state->subdoc_tags list
* if state->in_relayout and style_sheets_prev_encountered
*/
/* normally we want to ignore uknown tags
* but we need to pay some special attention
* to these tags in the relayout state
*/
if(tag->type == P_UNKNOWN )
{
rv = PUSH_TAG_ERROR;
return(rv);
}
}
for( k = 0; k < sizeOfParamsTable; k++ )
tableParamValues[k] = NULL;
PA_FetchRequestedNameValues( tag, tableParams, sizeOfParamsTable, tableParamValues, win_csid );
tag_name_attr = tableParamValues[0];
tag_name = tag_name_attr;
class_name = tableParamValues[1];
id_name = tableParamValues[2];
style_value = tableParamValues[3];
/* normally we want to ignore uknown tags
* but we need to pay some special attention
* to these tags in the relayout state
*/
if(tag->type == P_UNKNOWN && !tag_name_attr)
{
rv = PUSH_TAG_ERROR;
XP_FREEIF(style_value);
XP_FREEIF(tag_name_attr);
XP_FREEIF(class_name);
XP_FREEIF(id_name);
return(rv);
}
/*
*style_value freed in lo_ProcessStyleAttribute
*/
if(lo_ProcessStyleAttribute(context, state, tag, style_value))
{
/* enable the tag stack */
STYLESTACK_SetSaveOn(state->top_state->style_stack, TRUE);
rv = PUSH_TAG_BLOCKED;
XP_FREEIF(tag_name_attr);
XP_FREEIF(class_name);
XP_FREEIF(id_name);
return(rv);
}
if(id_name)
{
new_name = CSS_ConvertToJSCompatibleName(id_name, FALSE);
if(new_name)
{
XP_FREE(id_name);
id_name = new_name;
}
}
else
id_name = PR_smprintf(NSIMPLICITID"%ld", state->top_state->tag_count);
if(class_name)
{
new_name = CSS_ConvertToJSCompatibleName(class_name, FALSE);
if(new_name)
{
XP_FREE(class_name);
class_name = new_name;
}
}
if(!tag_name)
{
temp_tag_name = (char*)pa_PrintTagToken((int32)tag->type);
tag_name = XP_STRDUP( temp_tag_name );
}
/* call into the style stack class */
rv = STYLESTACK_PushTag(state->top_state->style_stack,
tag_name,
class_name,
id_name);
return(rv);
}
/* look for implicit tag pops. For instance the close of a TR tag
* implicitly pops all TD tags and any other open tags
*/
PUBLIC XP_Bool
LO_ImplicitPop(MWContext *context, lo_DocState **state, PA_Tag *tag)
{
switch(tag->type)
{
case P_LIST_ITEM:
/* NOTE: there should be no end LI */
if(tag->is_end)
return FALSE;
LO_PopAllTagsAbove(context,
state,
P_LIST_ITEM,
P_LIST_ITEM,
P_NUM_LIST,
P_UNUM_LIST);
return TRUE;
case P_TABLE_DATA:
LO_PopAllTagsAbove(context,
state,
P_TABLE_DATA,
P_TABLE_DATA,
P_TABLE_ROW,
P_TABLE);
return TRUE;
case P_TABLE_ROW:
LO_PopAllTagsAbove(context,
state,
P_TABLE_ROW,
P_TABLE_ROW,
P_TABLE,
P_UNKNOWN);
return TRUE;
case P_TABLE:
/* table begins don't implicitly close tables */
if(tag->is_end)
LO_PopAllTagsAbove(context,
state,
P_TABLE,
P_TABLE,
P_UNKNOWN,
P_UNKNOWN);
return TRUE;
default:
return FALSE;
}
}
PUBLIC void
LO_PopStyleTagByIndex(MWContext *context, lo_DocState **state,
TagType tag_type, int32 index)
{
StyleStruct * top_style;
char *property, *page_break_property;
SS_Number *bottom_margin;
SS_Number *bottom_padding;
SS_Number *pop_table;
if(!(*state) || !context || !(*state)->top_state->style_stack || index < 0)
return;
top_style = STYLESTACK_GetStyleByIndex((*state)->top_state->style_stack,index);
if(!top_style)
return;
#ifdef DEBUG
{
TagStruct * stag = STYLESTACK_GetTagByIndex((*state)->top_state->style_stack, 0);
stag = NULL; /* set breakpoint here for viewing */
}
#endif
page_break_property = STYLESTRUCT_GetString(top_style, PAGE_BREAK_AFTER_STYLE);
if (page_break_property)
{
if(!strcasecomp(page_break_property, "auto"))
{
/* not currently supported */
}
else if(!strcasecomp(page_break_property, "always"))
{
/* not currently supported */
}
else if(!strcasecomp(page_break_property, "left"))
{
/* not currently supported */
}
else if(!strcasecomp(page_break_property, "right"))
{
/* not currently supported */
}
XP_FREE(page_break_property);
}
/* calculate the bottom margin here since we need the original font
* information before closing the table, but don't apply it until
* after the table is closed
*/
bottom_margin = STYLESTRUCT_GetNumber(top_style, BOTTOMMARGIN_STYLE);
LO_AdjustSSUnits(bottom_margin, BOTTOMMARGIN_STYLE, context, *state);
if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_PRE)) != NULL)
{
(*state)->preformatted = PRE_TEXT_NO;
FE_EndPreSection(context);
XP_FREE(property);
}
else if((property = STYLESTRUCT_GetString(top_style,
STYLE_NEED_TO_RESET_PRE)) != NULL)
{
/* @@@ hack
* use this stack to reset pre if we exited from it
* via a whiteSpace: normal directive
*/
(*state)->preformatted = PRE_TEXT_YES;
FE_BeginPreSection(context);
XP_FREE(property);
}
/* pop any necessary stacks */
if((pop_table = STYLESTRUCT_GetNumber(top_style, STYLE_NEED_TO_POP_TABLE)) != NULL)
{
lo_TopState *top_state;
int32 doc_id;
if(pop_table->value)
{
/* unset the property to prevent reentrancy from popping the
* table twice
*/
STYLESTRUCT_SetString(top_style,
STYLE_NEED_TO_POP_TABLE,
"0",
MAX_STYLESTRUCT_PRIORITY);
lo_CloseTable(context, *state);
/* get the new current state */
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
*state = lo_TopSubState(top_state);
}
STYLESTRUCT_FreeSSNumber(top_style, pop_table);
}
else
{
/* add bottom padding */
bottom_padding = STYLESTRUCT_GetNumber(top_style, BOTTOMPADDING_STYLE);
LO_AdjustSSUnits(bottom_padding, BOTTOMPADDING_STYLE, context, *state);
if(bottom_padding && bottom_padding->value > 0)
{
int32 move_size = FEUNITS_Y((int32)bottom_padding->value, context);
lo_SetSoftLineBreakState(context, *state, FALSE, 1);
(*state)->y += move_size;
}
STYLESTRUCT_FreeSSNumber(top_style, bottom_padding);
}
property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_ALIGNMENT);
if(property)
{
lo_AlignStack *lptr;
/* flush the line to get the alignment correct */
lo_SetSoftLineBreakState(context, *state, FALSE, 1);
lptr = lo_PopAlignment(*state);
if (lptr != NULL)
XP_DELETE(lptr);
XP_FREE(property);
}
/* pop the last List */
if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_MARGINS)) != NULL)
{
lo_ListStack *lptr;
XP_FREE(property);
if((*state)->list_stack)
{
lptr = lo_PopList(*state, NULL);
if (lptr != NULL)
XP_DELETE(lptr);
(*state)->left_margin = (*state)->list_stack->old_left_margin;
(*state)->right_margin = (*state)->list_stack->old_right_margin;
lo_SetSoftLineBreakState(context, *state, FALSE, 1);
(*state)->x = (*state)->left_margin;
}
}
if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_LIST)) != NULL)
{
XP_FREE(property);
lo_TeardownList(context, *state, NULL);
}
/* apply bottom margins */
if(bottom_margin && bottom_margin->value > 0)
{
int32 move_size = FEUNITS_Y((int32)bottom_margin->value, context);
lo_SetSoftLineBreakState(context, *state, FALSE, 1);
(*state)->y += move_size;
}
STYLESTRUCT_FreeSSNumber(top_style, bottom_margin);
property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_LINE_HEIGHT);
if(property)
{
lo_LineHeightStack *lptr;
lptr = lo_PopLineHeight(*state);
if (lptr != NULL)
XP_DELETE(lptr);
XP_FREE(property);
}
/* pop layers last since they get pushed first */
property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_LAYER);
if(property)
{
lo_EndLayer(context, *state, PR_TRUE);
}
if((property = STYLESTRUCT_GetString(top_style, STYLE_NEED_TO_POP_FONT)) != NULL)
{
XP_FREE(property);
lo_PopFont(*state, tag_type);
}
if((property = STYLESTRUCT_GetString(top_style,
STYLE_NEED_TO_POP_CONTENT_HIDING)) != NULL)
{
XP_FREE(property);
(*state)->hide_content = FALSE;
}
STYLESTACK_PopTagByIndex((*state)->top_state->style_stack,(char*)pa_PrintTagToken((int32)tag_type), index);
}
PUBLIC void
LO_PopStyleTag(MWContext *context, lo_DocState **state, PA_Tag *tag)
{
/* look for tags that need to be implicitly pop'd */
if(!LO_ImplicitPop(context, state, tag))
LO_PopStyleTagByIndex(context, state, tag->type, 0);
}
PRIVATE int
compare_tag_type_and_name(TagType tag_type, char *tag_name)
{
return strcasecomp((char *)pa_PrintTagToken((int32)tag_type), tag_name);
}
/* pops all the tags in the stack above the type specified.
*
* the not_below_this argument if non P_UNKNOWN specifies a tag type to
* halt the search on. By default this will search to the
* bottom of the stack.
*
* for instance to pop all tags above TR but not below TABLE
* LO_PopAllTagsAbove(context, state, P_TR, P_TABLE, P_UNKNOWN, P_UNKNOWN)
*
* This function pops the tag of the specified type. (so TR would NOT still
* be on the stack)
*
* returns TRUE if tag_type was found and popped.
* returns FALSE if tag_type not found or error
*/
PUBLIC XP_Bool
LO_PopAllTagsAbove(MWContext *context,
lo_DocState **state,
TagType tag_type,
TagType not_below_this,
TagType or_this,
TagType or_this_either)
{
TagStruct * top_tag;
int32 index = 0;
if(!(*state) || !context || !(*state)->top_state->style_stack || index < 0)
return FALSE;
top_tag = STYLESTACK_GetTagByIndex((*state)->top_state->style_stack,index);
while(top_tag)
{
if(!compare_tag_type_and_name(tag_type, top_tag->name))
{
/* found it */
/* pop it and all tags above in stack order */
for(; index > -1; index--)
LO_PopStyleTagByIndex(context, state, tag_type, 0);
return TRUE;
}
if( (not_below_this != P_UNKNOWN
&& !compare_tag_type_and_name(not_below_this, top_tag->name))
|| (or_this != P_UNKNOWN
&& !compare_tag_type_and_name(or_this, top_tag->name))
|| (or_this_either != P_UNKNOWN
&& !compare_tag_type_and_name(or_this_either, top_tag->name)))
return FALSE; /* not found */
index++;
top_tag = STYLESTACK_GetTagByIndex((*state)->top_state->style_stack, index);
}
return FALSE;
}
PRIVATE int32
lo_get_width_or_height_from_style_sheet(MWContext *context,
lo_DocState *state,
int type)
{
StyleStruct *top_style;
SS_Number *ss_val;
int32 val=0;
/* get the most current style struct */
if ( ! state->top_state->style_stack )
return 0;
top_style = STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0);
if(!top_style)
return 0;
/* get the property */
if(type == _STYLE_GET_WIDTH)
{
ss_val = STYLESTRUCT_GetNumber(top_style, WIDTH_STYLE);
}
else if(type == _STYLE_GET_HEIGHT)
{
ss_val = STYLESTRUCT_GetNumber(top_style, HEIGHT_STYLE);
}
else
{
XP_ASSERT(0);
return 0;
}
if(ss_val)
{
/* do unit conversions here */
LO_AdjustSSUnits(ss_val, WIDTH_STYLE, context, state);
/* convert to fe units */
if(type == _STYLE_GET_WIDTH)
val = FEUNITS_X((int32)ss_val->value, context);
else if(type == _STYLE_GET_HEIGHT)
val = FEUNITS_Y((int32)ss_val->value, context);
if(val < 1)
val = 1;
STYLESTRUCT_FreeSSNumber(top_style, ss_val);
return val;
}
return 0;
}
PUBLIC int32
LO_GetWidthFromStyleSheet(MWContext *context, lo_DocState *state)
{
return lo_get_width_or_height_from_style_sheet(context,
state,
_STYLE_GET_WIDTH);
}
PUBLIC int32
LO_GetHeightFromStyleSheet(MWContext *context, lo_DocState *state)
{
return lo_get_width_or_height_from_style_sheet(context,
state,
_STYLE_GET_HEIGHT);
}
#if 0
static XP_Bool
IsJSS(MWContext *context, PA_Tag *tag)
{
PA_Block buff;
char *str;
XP_Bool bResult = FALSE;
/* See if it's JavaScript style sheets or something else like CSS */
buff = lo_FetchParamValue(context, tag, PARAM_TYPE);
if (buff != NULL) {
PA_LOCK(str, char *, buff);
if (XP_STRCASECMP(str, "text/javascript") == 0)
bResult = TRUE;
PA_UNLOCK(buff);
PA_FREE(buff);
}
return bResult;
}
#endif /* 0 */
/* This code is just a wrapper around lo_ProcessScriptTag() */
void
lo_ProcessStyleTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
{
if(state && state->top_state && state->top_state->style_stack)
{
STYLESTACK_SetSaveOn(state->top_state->style_stack, TRUE);
}
lo_ProcessScriptTag(context, state, tag, NULL);
}