зеркало из https://github.com/mozilla/gecko-dev.git
1002 строки
24 KiB
C
1002 строки
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);
|
|
}
|