// $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" #include "TVirtualX.h" #include "snprintf.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; } if (!font) continue; 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; } }