// $Id: TGHtmlSizer.cxx,v 1.2 2007/05/04 20:33:16 rdm Exp $
// Author: Valeriy Onuchin 03/05/2007
/**************************************************************************
HTML widget for xclass. Based on tkhtml 1.28
Copyright (C) 1997-2000 D. Richard Hipp
Copyright (C) 2002-2003 Hector Peraza.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**************************************************************************/
// Routines used to compute the style and size of individual elements.
#include
#include
#include
#include "TGHtml.h"
#include "TImage.h"
////////////////////////////////////////////////////////////////////////////////
/// Get the current rendering style. In other words, get the style
/// that is currently on the top of the style stack.
SHtmlStyle_t TGHtml::GetCurrentStyle()
{
SHtmlStyle_t style;
if (fStyleStack) {
style = fStyleStack->fStyle;
} else {
style.fFont = NormalFont(2);
style.fColor = COLOR_Normal;
style.fBgcolor = COLOR_Background;
style.fSubscript = 0;
style.fAlign = ALIGN_Left;
style.fFlags = 0;
style.fExpbg = 0;
}
return style;
}
////////////////////////////////////////////////////////////////////////////////
/// Push a new rendering style onto the stack.
///
/// tag - Tag for this style. Normally the end-tag such as or .
/// style - The style to push
void TGHtml::PushStyleStack(int tag, SHtmlStyle_t style)
{
SHtmlStyleStack_t *p;
p = new SHtmlStyleStack_t;
p->fPNext = fStyleStack;
p->fType = tag;
p->fStyle = style;
fStyleStack = p;
}
////////////////////////////////////////////////////////////////////////////////
/// Pop a rendering style off of the stack.
///
/// The top-most style on the stack should have a tag equal to "tag".
/// If not, then we have an HTML coding error. Perhaps something
/// like this: "Some text Enphasized more text". It is an
/// interesting problem to figure out how to respond sanely to this
/// kind of error. Our solution is to keep popping the stack until
/// we find the correct tag, or until the stack is empty.
SHtmlStyle_t TGHtml::PopStyleStack(int tag)
{
int i, type;
SHtmlStyleStack_t *p;
static Html_u8_t priority[Html_TypeCount+1];
if (priority[Html_TABLE] == 0) {
for (i = 0; i <= Html_TypeCount; i++) priority[i] = 1;
priority[Html_TD] = 2;
priority[Html_EndTD] = 2;
priority[Html_TH] = 2;
priority[Html_EndTH] = 2;
priority[Html_TR] = 3;
priority[Html_EndTR] = 3;
priority[Html_TABLE] = 4;
priority[Html_EndTABLE] = 4;
}
if (tag <= 0 || tag > Html_TypeCount) {
CANT_HAPPEN;
return GetCurrentStyle();
}
while ((p = fStyleStack) != 0) {
type = p->fType;
if (type <= 0 || type > Html_TypeCount) {
CANT_HAPPEN;
return GetCurrentStyle();
}
if (type != tag && priority[type] > priority[tag]) {
return GetCurrentStyle();
}
fStyleStack = p->fPNext;
delete p;
if (type == tag) break;
}
return GetCurrentStyle();
}
////////////////////////////////////////////////////////////////////////////////
/// Change the font size on the given style by the delta-amount given
static void ScaleFont(SHtmlStyle_t *pStyle, int delta)
{
int size = FontSize(pStyle->fFont) + delta;
if (size < 0) {
delta -= size;
} else if (size > 6) {
delta -= size-6;
}
pStyle->fFont += delta;
}
////////////////////////////////////////////////////////////////////////////////
/// Add the STY_Invisible style to every token between p_first and p_last.
void TGHtml::MakeInvisible(TGHtmlElement *p_first, TGHtmlElement *p_last)
{
if (p_first == 0) return;
p_first = p_first->fPNext;
while (p_first && p_first != p_last) {
p_first->fStyle.fFlags |= STY_Invisible;
p_first = p_first->fPNext;
}
}
////////////////////////////////////////////////////////////////////////////////
/// For the markup , find out if the URL has been visited
/// before or not. Return COLOR_Visited or COLOR_Unvisited, as
/// appropriate.
int TGHtml::GetLinkColor(const char *zURL)
{
return IsVisited(zURL) ? COLOR_Visited : COLOR_Unvisited;
}
////////////////////////////////////////////////////////////////////////////////
/// Returns coordinates of string str.
static int *GetCoords(const char *str, int *nptr)
{
const char *cp = str;
char *ncp;
int *cr, i, n = 0, sz = 4;
cr = new int[sz];
while (cp) {
while (*cp && (!isdigit(*cp))) cp++;
if ((!*cp) || (!isdigit(*cp))) break;
cr[n] = (int) strtol(cp, &ncp, 10);
if (cp == ncp) break;
cp = ncp;
n++;
if (n >= sz) {
int *tmp = new int[sz+4];
for (i = 0; i < sz; ++i) tmp[i] = cr[i];
delete[] cr;
cr = tmp;
sz += 4;
}
}
*nptr = n;
return cr;
}
////////////////////////////////////////////////////////////////////////////////
/// This routine adds information to the input texts that doesn't change
/// when the display is resized or when new fonts are selected, etc.
/// Mostly this means adding style attributes. But other constant
/// information (such as numbering on and images used for
)
/// is also obtained. The key is that this routine is only called
/// once, where the sizer and layout routines can be called many times.
///
/// This routine is called whenever the list of elements grows. The
/// style stack is stored as part of the HTML widget so that we can
/// always continue where we left off the last time.
///
/// In addition to adding style, this routine will invoke methods
/// needed to acquire information about a markup. The IsVisitied()
/// method is called for each and the GetImage() is called
/// for each
or for each that has a SRC= field.
///
/// When a markup is inserted or deleted from the token list, the
/// style routine must be completely rerun from the beginning. So
/// what we said above, that this routine is only run once, is not
/// strictly true.
void TGHtml::AddStyle(TGHtmlElement *p)
{
SHtmlStyle_t style; // Current style
int size; // A new font size
int i; // Loop counter
int paraAlign; // Current paragraph alignment
int rowAlign; // Current table row alignment
SHtmlStyle_t nextStyle; // Style for next token if useNextStyle==1
int useNextStyle = 0; // True if nextStyle is valid
const char *z; // A tag parameter's value
// The size of header fonts relative to the current font size
static int header_sizes[] = { +2, +1, 1, 1, -1, -1 };
// Don't allow recursion
if (fFlags & STYLER_RUNNING) return;
fFlags |= STYLER_RUNNING;
// Load the style state out of the TGHtml object and into local
// variables. This is purely a matter of convenience...
style = GetCurrentStyle();
nextStyle = style; //ia: nextStyle was not initialized
paraAlign = fParaAlignment;
rowAlign = fRowAlignment;
// Loop over tokens
while (fPFirst && p) {
switch (p->fType) {
case Html_A:
if (fAnchorStart) {
style = PopStyleStack(Html_EndA);
fAnchorStart = 0;
fAnchorFlags = 0;
}
z = p->MarkupArg("href", 0);
if (z) {
style.fColor = GetLinkColor(z);
if (fUnderlineLinks) style.fFlags |= STY_Underline;
fAnchorFlags |= STY_Anchor;
PushStyleStack(Html_EndA, style);
fAnchorStart = (TGHtmlAnchor *) p;
}
break;
case Html_EndA:
if (fAnchorStart) {
((TGHtmlRef *)p)->fPOther = fAnchorStart;
style = PopStyleStack(Html_EndA);
fAnchorStart = 0;
fAnchorFlags = 0;
}
break;
case Html_MAP:
break;
case Html_EndMAP:
break;
case Html_AREA: {
TGHtmlMapArea *area = (TGHtmlMapArea *) p;
z = p->MarkupArg("shape", 0);
area->fMType = HTML_MAP_RECT;
if (z) {
if (strcasecmp(z, "circle") == 0) {
area->fMType = HTML_MAP_CIRCLE;
} else if (strcasecmp(z,"poly") == 0) {
area->fMType = HTML_MAP_POLY;
}
}
z = p->MarkupArg("coords", 0);
if (z) {
area->fCoords = GetCoords(z, &area->fNum);
}
break;
}
case Html_ADDRESS:
case Html_EndADDRESS:
case Html_BLOCKQUOTE:
case Html_EndBLOCKQUOTE:
paraAlign = ALIGN_None;
break;
case Html_APPLET:
if (0 /* has ProcessApplet() */) {
nextStyle = style;
nextStyle.fFlags |= STY_Invisible;
PushStyleStack(Html_EndAPPLET, nextStyle);
useNextStyle = 1;
} else {
PushStyleStack(Html_EndAPPLET, style);
}
break;
case Html_B:
style.fFont = BoldFont(style.fFont);
PushStyleStack(Html_EndB, style);
break;
case Html_BODY:
z = p->MarkupArg("text", 0);
if (z) {
//FreeColor(fApColor[COLOR_Normal]);
fApColor[COLOR_Normal] = AllocColor(z);
}
z = p->MarkupArg("bgcolor", 0);
if (z) {
//FreeColor(fApColor[COLOR_Background]);
fApColor[COLOR_Background] = AllocColor(z);
SetBackgroundColor(fApColor[COLOR_Background]->fPixel);
SetBackgroundPixmap(0);
}
z = p->MarkupArg("link", 0);
if (z) {
//FreeColor(fApColor[COLOR_Unvisited]);
fApColor[COLOR_Unvisited] = AllocColor(z);
}
z = p->MarkupArg("vlink", 0);
if (z) {
//FreeColor(fApColor[COLOR_Visited]);
fApColor[COLOR_Visited] = AllocColor(z);
}
z = p->MarkupArg("alink", 0);
if (z) {
}
z = p->MarkupArg("background", 0);
if (z) {
z = ResolveUri(z);
if (z) {
TImage *img = LoadImage(z, 0, 0);
if (img) {
#if 0
SetupBackgroundPic(img->GetPicture());
#else
GCValues_t gcv;
// unsigned int mask;
// mask = kGCTile | kGCFillStyle | kGCGraphicsExposures;
gcv.fTile = img->GetPixmap();
gcv.fFillStyle = kFillTiled;
gcv.fGraphicsExposures = kTRUE;
fCanvas->SetBackgroundPixmap(img->GetPixmap());
gVirtualX->ChangeGC(fWhiteGC.GetGC(), &gcv);
//NeedRedraw(TGRectangle(fVisible, fCanvas->GetSize()));
#endif
fBgImage = img;//delete img;
}
delete [] z;
}
}
break;
case Html_EndBODY:
break;
case Html_EndAPPLET:
case Html_EndB:
case Html_EndBIG:
case Html_EndCENTER:
case Html_EndCITE:
case Html_EndCODE:
case Html_EndCOMMENT:
case Html_EndDFN:
case Html_EndEM:
case Html_EndFONT:
case Html_EndI:
case Html_EndKBD:
case Html_EndMARQUEE:
case Html_EndNOBR:
case Html_EndNOFRAMES:
case Html_EndNOSCRIPT:
case Html_EndNOEMBED:
case Html_EndS:
case Html_EndSAMP:
case Html_EndSMALL:
case Html_EndSTRIKE:
case Html_EndSTRONG:
case Html_EndSUB:
case Html_EndSUP:
case Html_EndTITLE:
case Html_EndTT:
case Html_EndU:
case Html_EndVAR:
style = PopStyleStack(p->fType);
break;
case Html_BASE:
z = p->MarkupArg("href", 0);
if (z) {
char *z1 = ResolveUri(z);
if (z1 != 0) {
if (fZBaseHref) delete[] fZBaseHref;
fZBaseHref = z1;
}
}
break;
case Html_EndDIV:
paraAlign = ALIGN_None;
style = PopStyleStack(p->fType);
break;
case Html_EndBASEFONT:
style = PopStyleStack(Html_EndBASEFONT);
style.fFont = FontFamily(style.fFont) + 2;
break;
case Html_BIG:
ScaleFont(&style, 1);
PushStyleStack(Html_EndBIG, style);
break;
case Html_CAPTION:
paraAlign = p->GetAlignment(paraAlign);
break;
case Html_EndCAPTION:
paraAlign = ALIGN_None;
break;
case Html_CENTER:
paraAlign = ALIGN_None;
style.fAlign = ALIGN_Center;
PushStyleStack(Html_EndCENTER, style);
break;
case Html_CITE:
style.fFont = ItalicFont(style.fFont);
PushStyleStack(Html_EndCITE, style);
break;
case Html_CODE:
style.fFont = CWFont(style.fFont);
PushStyleStack(Html_EndCODE, style);
break;
case Html_COMMENT:
style.fFlags |= STY_Invisible;
PushStyleStack(Html_EndCOMMENT, style);
break;
case Html_DD:
if (fInnerList && fInnerList->fType == Html_DL) {
((TGHtmlRef *)p)->fPOther = fInnerList;
} else {
((TGHtmlRef *)p)->fPOther = 0;
}
fInDt = 0;
break;
case Html_DFN:
style.fFont = ItalicFont(style.fFont);
PushStyleStack(Html_EndDFN, style);
break;
case Html_DIR:
case Html_MENU:
case Html_UL: {
TGHtmlListStart *list = (TGHtmlListStart *) p;
list->fLPrev = fInnerList;
list->fCnt = 0;
fInnerList = list;
if (list->fLPrev == 0) {
list->fLtype = LI_TYPE_Bullet1;
list->fCompact = (list->MarkupArg("compact", 0) != 0);
} else if (list->fLPrev->fLPrev == 0) {
list->fLtype = LI_TYPE_Bullet2;
list->fCompact = 1;
} else {
list->fLtype = LI_TYPE_Bullet3;
list->fCompact = 1;
}
list->fLtype = list->GetUnorderedListType(list->fLtype);
break;
}
case Html_EndDL:
fInDt = 0;
/* Fall thru into the next case */
case Html_EndDIR:
case Html_EndMENU:
case Html_EndOL:
case Html_EndUL:
((TGHtmlRef *)p)->fPOther = fInnerList;
if (fInnerList) fInnerList = fInnerList->fLPrev;
break;
case Html_DIV:
paraAlign = ALIGN_None;
style.fAlign = p->GetAlignment(style.fAlign);
PushStyleStack(Html_EndDIV, style);
break;
case Html_DT:
if (fInnerList && fInnerList->fType == Html_DL) {
((TGHtmlRef *)p)->fPOther = fInnerList;
} else {
((TGHtmlRef *)p)->fPOther = 0;
}
fInDt = STY_DT;
break;
case Html_EndDD:
case Html_EndDT:
fInDt = 0;
break;
case Html_DL: {
TGHtmlListStart *list = (TGHtmlListStart *) p;
list->fLPrev = fInnerList;
list->fCnt = 0;
fInnerList = list;
list->fCompact = (list->MarkupArg("compact", 0) != 0);
fInDt = 0;
break;
}
case Html_EM:
style.fFont = ItalicFont(style.fFont);
PushStyleStack(Html_EndEM, style);
break;
case Html_EMBED:
break;
case Html_BASEFONT:
case Html_FONT:
z = p->MarkupArg("size", 0);
if (z && !fOverrideFonts) {
if (*z == '-') {
size = FontSize(style.fFont) - atoi(&z[1]) +1;
} else if (*z == '+') {
size = FontSize(style.fFont) + atoi(&z[1]) +1;
} else {
size = atoi(z);
}
if (size <= 0) size = 1;
if (size >= N_FONT_SIZE) size = N_FONT_SIZE - 1;
style.fFont = FontFamily(style.fFont) + size - 1;
}
z = p->MarkupArg("color", 0);
if (z && *z && !fOverrideColors) style.fColor = GetColorByName(z);
PushStyleStack(p->fType == Html_FONT ?
Html_EndFONT : Html_EndBASEFONT, style);
break;
case Html_FORM: {
TGHtmlForm *form = (TGHtmlForm *) p;
const char *zUrl;
const char *zMethod;
TGString cmd("");
// int result;
char zToken[50];
fFormStart = 0;
//form->fFormId = 0;
zUrl = p->MarkupArg("action", 0);
if (zUrl == 0) zUrl = fZBase;
zUrl = ResolveUri(zUrl);
if (zUrl == 0) zUrl = StrDup("");
zMethod = p->MarkupArg("method", "GET");
snprintf(zToken, 50, " %d form ", form->fFormId);
cmd.Append("Form:");
cmd.Append(zToken);
cmd.Append(zUrl);
cmd.Append(" ");
cmd.Append(zMethod);
cmd.Append(" { ");
AppendArglist(&cmd, (TGHtmlMarkupElement *) p);
cmd.Append("} ");
/* result = */ FormCreate(form, zUrl, cmd.GetString());
delete[] zUrl;
/*if (result)*/ fFormStart = form;
break;
}
case Html_EndFORM:
((TGHtmlRef *)p)->fPOther = fFormStart;
if (fFormStart) fFormStart->fPEnd = p;
fFormStart = 0;
break;
case Html_H1:
case Html_H2:
case Html_H3:
case Html_H4:
case Html_H5:
case Html_H6:
if (!fInTr) paraAlign = ALIGN_None;
i = (p->fType - Html_H1) / 2 + 1;
if (i >= 1 && i <= 6) {
ScaleFont(&style, header_sizes[i-1]);
}
style.fFont = BoldFont(style.fFont);
style.fAlign = p->GetAlignment(style.fAlign);
PushStyleStack(Html_EndH1, style);
break;
case Html_EndH1:
case Html_EndH2:
case Html_EndH3:
case Html_EndH4:
case Html_EndH5:
case Html_EndH6:
paraAlign = ALIGN_None;
style = PopStyleStack(Html_EndH1);
break;
case Html_HR:
nextStyle = style;
style.fAlign = p->GetAlignment(ALIGN_None);
useNextStyle = 1;
break;
case Html_I:
style.fFont = ItalicFont(style.fFont);
PushStyleStack(Html_EndI, style);
break;
case Html_IMG:
if (style.fFlags & STY_Invisible) break;
((TGHtmlImageMarkup *)p)->fPImage = GetImage((TGHtmlImageMarkup *) p);
break;
case Html_OPTION:
break;
case Html_INPUT:
((TGHtmlInput *)p)->fPForm = fFormStart;
////ControlSize((TGHtmlInput *) p);
break;
case Html_KBD:
style.fFont = CWFont(style.fFont);
PushStyleStack(Html_EndKBD, style);
break;
case Html_LI:
if (fInnerList) {
TGHtmlLi *li = (TGHtmlLi *) p;
li->fLtype = fInnerList->fLtype;
if (fInnerList->fType == Html_OL) {
z = li->MarkupArg("value", 0);
if (z) {
int n = atoi(z);
if (n > 0) {
li->fCnt = n;
fInnerList->fCnt = n+1;
}
} else {
li->fCnt = fInnerList->fCnt++;
}
li->fLtype = li->GetOrderedListType(li->fLtype);
} else {
li->fLtype = li->GetUnorderedListType(li->fLtype);
}
} else {
p->fFlags &= ~HTML_Visible;
}
break;
case Html_MARQUEE:
style.fFlags |= STY_Invisible;
PushStyleStack(Html_EndMARQUEE, style);
break;
case Html_NOBR:
style.fFlags |= STY_NoBreak;
PushStyleStack(Html_EndNOBR, style);
break;
case Html_NOFRAMES:
if (0 /* has ProcessFrame()*/) {
nextStyle = style;
nextStyle.fFlags |= STY_Invisible;
PushStyleStack(Html_EndNOFRAMES, nextStyle);
useNextStyle = 1;
} else {
PushStyleStack(Html_EndNOFRAMES, style);
}
break;
case Html_NOEMBED:
if (0 /* has ProcessScript() && HasScript */) {
nextStyle = style;
nextStyle.fFlags |= STY_Invisible;
PushStyleStack(Html_EndNOEMBED, nextStyle);
useNextStyle = 1;
} else {
PushStyleStack(Html_EndNOEMBED, style);
}
break;
case Html_NOSCRIPT:
if (0 /* has ProcessScript() && HasScript */) {
nextStyle = style;
nextStyle.fFlags |= STY_Invisible;
PushStyleStack(Html_EndNOSCRIPT, nextStyle);
useNextStyle = 1;
} else {
PushStyleStack(Html_EndNOSCRIPT, style);
}
break;
case Html_OL: {
TGHtmlListStart *list = (TGHtmlListStart *) p;
list->fLPrev = fInnerList;
list->fLtype = list->GetOrderedListType(LI_TYPE_Enum_1);
list->fCnt = 1;
z = list->MarkupArg("start", 0);
if (z) {
int n = atoi(z);
if (n > 0) list->fCnt = n;
}
list->fCompact = (fInnerList != 0 || list->MarkupArg("compact", 0) != 0);
fInnerList = list;
break;
}
case Html_P:
paraAlign = p->GetAlignment(ALIGN_None);
break;
case Html_EndP:
paraAlign = ALIGN_None;
break;
case Html_PRE:
case Html_LISTING:
case Html_XMP:
case Html_PLAINTEXT:
paraAlign = ALIGN_None;
style.fFont = CWFont(style.fFont);
style.fFlags |= STY_Preformatted;
PushStyleStack(Html_EndPRE, style);
break;
case Html_EndPRE:
case Html_EndLISTING:
case Html_EndXMP:
style = PopStyleStack(Html_EndPRE);
break;
case Html_S:
style.fFlags |= STY_StrikeThru;
PushStyleStack(Html_EndS, style);
break;
case Html_SCRIPT: {
char *result;
result = ProcessScript((TGHtmlScript *) p); // fZText[script->nStart .. script->nScript]
if (result) {
TGHtmlElement *b2 = p->fPNext, *b3, *e1 = p, *e2 = b2, *e3;
if (e2) while (e2->fPNext) e2 = e2->fPNext;
TokenizerAppend(result);
if (e2 && e2 != p && ((e3 = b3 = e2->fPNext))) {
while (e3->fPNext) e3 = e3->fPNext;
e1->fPNext = b3;
e2->fPNext = 0; b2->fPPrev = e3;
e3->fPNext = b2; b3->fPPrev = e1;
}
delete[] result;
}
nextStyle = style;
style.fFlags |= STY_Invisible;
useNextStyle = 1;
break;
}
case Html_SELECT:
((TGHtmlInput *)p)->fPForm = fFormStart;
nextStyle.fFlags |= STY_Invisible;
useNextStyle = 1;
PushStyleStack(Html_EndSELECT, style);
fFormElemStart = (TGHtmlInput *) p;
break;
case Html_EndSELECT:
style = PopStyleStack(Html_EndSELECT);
if (fFormElemStart && fFormElemStart->fType == Html_SELECT) {
((TGHtmlRef *)p)->fPOther = fFormElemStart;
MakeInvisible(((TGHtmlRef *)p)->fPOther, p);
} else {
((TGHtmlRef *)p)->fPOther = 0;
}
fFormElemStart = 0;
break;
case Html_STRIKE:
style.fFlags |= STY_StrikeThru;
PushStyleStack(Html_EndSTRIKE, style);
break;
case Html_STYLE:
// Ignore style sheets
break;
case Html_SAMP:
style.fFont = CWFont(style.fFont);
PushStyleStack(Html_EndSAMP, style);
break;
case Html_SMALL:
ScaleFont(&style, -1);
PushStyleStack(Html_EndSMALL, style);
break;
case Html_STRONG:
style.fFont = BoldFont(style.fFont);
PushStyleStack(Html_EndSTRONG, style);
break;
case Html_SUB:
ScaleFont(&style, -1);
if (style.fSubscript > -6 ) style.fSubscript--;
PushStyleStack(Html_EndSUB, style);
break;
case Html_SUP:
ScaleFont(&style, -1);
if (style.fSubscript < 6) style.fSubscript++;
PushStyleStack(Html_EndSUP, style);
break;
case Html_TABLE:
paraAlign = ALIGN_None;
nextStyle = style;
if (style.fFlags & STY_Preformatted) {
nextStyle.fFlags &= ~STY_Preformatted;
style.fFlags |= STY_Preformatted;
}
nextStyle.fAlign = ALIGN_Left;
z = p->MarkupArg("bgcolor", 0);
if (z && *z && !fOverrideColors) {
style.fBgcolor = nextStyle.fBgcolor = GetColorByName(z);
style.fExpbg = 1;
// } else {
// nextStyle.fBgcolor = COLOR_Background;
}
TableBgndImage(p);
PushStyleStack(Html_EndTABLE, nextStyle);
useNextStyle = 1;
fInTd = 0;
fInTr = 0;
break;
case Html_EndTABLE:
paraAlign = ALIGN_None;
if (fInTd) {
style = PopStyleStack(Html_EndTD);
fInTd = 0;
}
if (fInTr) {
style = PopStyleStack(Html_EndTR);
fInTr = 0;
}
style = PopStyleStack(p->fType);
break;
case Html_TD:
if (fInTd) style = PopStyleStack(Html_EndTD);
fInTd = 1;
paraAlign = p->GetAlignment(rowAlign);
z = p->MarkupArg("bgcolor", 0);
if (z && *z && !fOverrideColors) {
style.fBgcolor = GetColorByName(z);
style.fExpbg = 1;
}
TableBgndImage(p);
PushStyleStack(Html_EndTD, style);
break;
case Html_TEXTAREA:
((TGHtmlInput *)p)->fPForm = fFormStart;
nextStyle = style;
nextStyle.fFlags |= STY_Invisible;
PushStyleStack(Html_EndTEXTAREA, nextStyle);
fFormElemStart = (TGHtmlInput *) p;
useNextStyle = 1;
break;
case Html_EndTEXTAREA:
style = PopStyleStack(Html_EndTEXTAREA);
if (fFormElemStart && fFormElemStart->fType == Html_TEXTAREA) {
((TGHtmlRef *)p)->fPOther = fFormElemStart;
} else {
((TGHtmlRef *)p)->fPOther = 0;
}
fFormElemStart = 0;
break;
case Html_TH:
//paraAlign = p->GetAlignment(rowAlign);
if (fInTd) style = PopStyleStack(Html_EndTD);
paraAlign = p->GetAlignment(ALIGN_Center);
style.fFont = BoldFont(style.fFont);
z = p->MarkupArg("bgcolor", 0);
if (z && *z && !fOverrideColors) {
style.fBgcolor = GetColorByName(z);
style.fExpbg = 1;
}
PushStyleStack(Html_EndTD, style);
fInTd = 1;
break;
case Html_TR:
if (fInTd) {
style = PopStyleStack(Html_EndTD);
fInTd = 0;
}
if (fInTr) {
style = PopStyleStack(Html_EndTR);
}
rowAlign = p->GetAlignment(ALIGN_None);
z = p->MarkupArg("bgcolor", 0);
if (z && *z && !fOverrideColors) {
style.fBgcolor = GetColorByName(z);
style.fExpbg = 1;
}
TableBgndImage(p);
PushStyleStack(Html_EndTR, style);
fInTr = 1;
break;
case Html_EndTR:
if (fInTd) {
style = PopStyleStack(Html_EndTD);
fInTd = 0;
}
style = PopStyleStack(Html_EndTR);
fInTr = 0;
paraAlign = ALIGN_None;
rowAlign = ALIGN_None;
break;
case Html_EndTD:
case Html_EndTH:
style = PopStyleStack(Html_EndTD);
fInTd = 0;
paraAlign = ALIGN_None;
//rowAlign = ALIGN_None;
break;
case Html_TITLE:
style.fFlags |= STY_Invisible;
PushStyleStack(Html_EndTITLE, style);
break;
case Html_TT:
style.fFont = CWFont(style.fFont);
PushStyleStack(Html_EndTT, style);
break;
case Html_U:
style.fFlags |= STY_Underline;
PushStyleStack(Html_EndU, style);
break;
case Html_VAR:
style.fFont = ItalicFont(style.fFont);
PushStyleStack(Html_EndVAR, style);
break;
default:
break;
}
p->fStyle = style;
p->fStyle.fFlags |= fAnchorFlags | fInDt;
if (paraAlign != ALIGN_None) {
p->fStyle.fAlign = paraAlign;
}
if (useNextStyle) {
style = nextStyle;
style.fExpbg = 0;
useNextStyle = 0;
}
TRACE(HtmlTrace_Style,
("Style font=%02d color=%02d bg=%02d "
"align=%d flags=0x%04x token=%s\n",
p->fStyle.fFont, p->fStyle.fColor, p->fStyle.fBgcolor,
p->fStyle.fAlign, p->fStyle.fFlags, DumpToken(p)));
p = p->fPNext;
}
// Copy state information back into the TGHtml object for safe keeping.
fParaAlignment = paraAlign;
fRowAlignment = rowAlign;
fFlags &= ~STYLER_RUNNING;
}
////////////////////////////////////////////////////////////////////////////////
/// Set background picture of a html table.
void TGHtml::TableBgndImage(TGHtmlElement *p)
{
const char *z;
z = p->MarkupArg("background", 0);
if (!z) return;
char *z1 = ResolveUri(z);
TImage *img = LoadImage(z1, 0, 0);
delete [] z1;
switch (p->fType) {
case Html_TABLE: {
TGHtmlTable *table = (TGHtmlTable *) p;
if (table->fBgImage) delete table->fBgImage;
table->fBgImage = img;
break;
}
case Html_TR: {
TGHtmlRef *ref = (TGHtmlRef *) p;
if (ref->fBgImage) delete ref->fBgImage;
ref->fBgImage = img;
break;
}
case Html_TH:
case Html_TD: {
TGHtmlCell *cell = (TGHtmlCell *) p;
if (cell->fBgImage) delete cell->fBgImage;
cell->fBgImage = img;
break;
}
default:
if (img) delete img;
break;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Compute the size of all elements in the widget. Assume that a style has
/// already been assigned to all elements.
///
/// Some of the elements might have already been sized. Refer to the
/// fLastSized and only compute sizes for elements that follow this one. If
/// fLastSized is 0, then size everything.
///
/// This routine only computes the sizes of individual elements. The size of
/// aggregate elements (like tables) are computed separately.
///
/// The HTML_Visible flag is also set on every element that results in ink on
/// the page.
///
/// This routine may invoke a callback procedure which could delete the HTML
/// widget.
void TGHtml::Sizer()
{
TGHtmlElement *p;
int iFont = -1;
TGFont *font=0;
int spaceWidth = 0;
FontMetrics_t fontMetrics;
const char *z;
int stop = 0;
if (fPFirst == 0) return;
if (fLastSized == 0) {
p = fPFirst;
} else {
p = fLastSized->fPNext;
}
// coverity[dead_error_line]
for (; !stop && p; p = p ? p->fPNext : 0) {
if (p->fStyle.fFlags & STY_Invisible) {
p->fFlags &= ~HTML_Visible;
continue;
}
if (iFont != (int)p->fStyle.fFont) {
iFont = p->fStyle.fFont;
font = GetFont(iFont);
font->GetFontMetrics(&fontMetrics);
spaceWidth = 0;
}
switch (p->fType) {
case Html_Text: {
TGHtmlTextElement *text = (TGHtmlTextElement *) p;
text->fW = font->TextWidth(text->fZText, p->fCount);
p->fFlags |= HTML_Visible;
text->fDescent = fontMetrics.fDescent;
text->fAscent = fontMetrics.fAscent;
if (spaceWidth == 0) spaceWidth = font->TextWidth(" ", 1);
text->fSpaceWidth = spaceWidth;
break;
}
case Html_Space: {
TGHtmlSpaceElement *space = (TGHtmlSpaceElement *) p;
if (spaceWidth == 0) spaceWidth = font->TextWidth(" ", 1);
space->fW = spaceWidth;
space->fDescent = fontMetrics.fDescent;
space->fAscent = fontMetrics.fAscent;
p->fFlags &= ~HTML_Visible;
break;
}
case Html_TD:
case Html_TH: {
TGHtmlCell *cell = (TGHtmlCell *) p;
z = p->MarkupArg("rowspan", "1");
cell->fRowspan = z ? atoi(z) : 1;
z = p->MarkupArg("colspan", "1");
cell->fColspan = z ? atoi(z) : 1;
p->fFlags |= HTML_Visible;
break;
}
case Html_LI: {
TGHtmlLi *li = (TGHtmlLi *) p;
li->fDescent = fontMetrics.fDescent;
li->fAscent = fontMetrics.fAscent;
p->fFlags |= HTML_Visible;
break;
}
case Html_IMG: {
TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) p;
z = p->MarkupArg("usemap", 0);
if (z && *z == '#') {
image->fPMap = GetMap(z+1);
} else {
image->fPMap = 0;
}
p->fFlags |= HTML_Visible;
image->fRedrawNeeded = 0;
image->fTextAscent = fontMetrics.fAscent;
image->fTextDescent = fontMetrics.fDescent;
image->fAlign = GetImageAlignment(p);
if (image->fPImage == 0) {
image->fAscent = fontMetrics.fAscent;
image->fDescent = fontMetrics.fDescent;
image->fZAlt = p->MarkupArg("alt", "");
if (image->fZAlt == 0) image->fZAlt = "";
image->fW = font->TextWidth(image->fZAlt, strlen(image->fZAlt));
} else {
int w, h;
image->fINext = image->fPImage->fPList;
image->fPImage->fPList = image;
w = image->fPImage->fImage->GetWidth();
h = image->fPImage->fImage->GetHeight();
image->fH = h;
image->fW = w;
image->fAscent = h / 2;
image->fDescent = h - image->fAscent;
}
if ((z = p->MarkupArg("width", 0)) != 0) {
int w = atoi(z);
if (z[strlen(z)-1] == '%') w = 0; //// -- HP
if (w > 0) image->fW = w;
}
if ((z = p->MarkupArg("height", 0)) != 0) {
int h = atoi(z);
if (h > 0) image->fH = h;
}
#if 1 // --HP
if (image->fPImage == 0 && !*image->fZAlt) {
image->fAscent = image->fH / 2;
image->fDescent = image->fH - image->fAscent;
}
#endif
break;
}
case Html_TABLE:
p->fFlags |= HTML_Visible;
break;
case Html_HR:
p->fFlags |= HTML_Visible;
break;
case Html_APPLET:
case Html_EMBED:
case Html_INPUT: {
TGHtmlInput *input = (TGHtmlInput *) p;
input->fTextAscent = fontMetrics.fAscent;
input->fTextDescent = fontMetrics.fDescent;
stop = ControlSize(input);
break;
}
case Html_SELECT:
case Html_TEXTAREA: {
TGHtmlInput *input = (TGHtmlInput *) p;
input->fTextAscent = fontMetrics.fAscent;
input->fTextDescent = fontMetrics.fDescent;
break;
}
case Html_EndSELECT:
case Html_EndTEXTAREA: {
TGHtmlRef *ref = (TGHtmlRef *) p;
if (ref->fPOther) {
((TGHtmlInput *)ref->fPOther)->fPEnd = p;
stop = ControlSize((TGHtmlInput *) ref->fPOther);
}
break;
}
default:
p->fFlags &= ~HTML_Visible;
break;
}
}
if (p) {
fLastSized = p;
} else {
fLastSized = fPLast;
}
}