ROOT  6.06/09
Reference Guide
TGHtmlIndex.cxx
Go to the documentation of this file.
1 // $Id: TGHtmlIndex.cxx,v 1.2 2007/05/20 23:22:13 rdm Exp $
2 // Author: Valeriy Onuchin 03/05/2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**************************************************************************
13 
14  HTML widget for xclass. Based on tkhtml 1.28
15  Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
16  Copyright (C) 2002-2003 Hector Peraza.
17 
18  This library is free software; you can redistribute it and/or
19  modify it under the terms of the GNU Library General Public
20  License as published by the Free Software Foundation; either
21  version 2 of the License, or (at your option) any later version.
22 
23  This library is distributed in the hope that it will be useful,
24  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26  Library General Public License for more details.
27 
28  You should have received a copy of the GNU Library General Public
29  License along with this library; if not, write to the Free
30  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 
32 **************************************************************************/
33 
34 // Routines that deal with indexes
35 
36 #include <ctype.h>
37 #include <string.h>
38 #include <stdlib.h>
39 
40 #include "TGHtml.h"
41 
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Return a pointer to the Nth TGHtmlElement in the list. If there
45 /// is no Nth element, return 0 if flag==0 and return either the first
46 /// or last element (whichever is closest) if flag!=0
47 
49 {
50  TGHtmlElement *p;
51  int n;
52 
53  if (N == 0) return fPFirst;
54 
55  if (N > fNToken / 2) {
56  // Start at the end and work back toward the beginning
57  for (p = fPLast, n = fNToken; p; p = p->fPPrev) {
58  if (p->fType != Html_Block) {
59  if (p->fElId == N) break;
60  --n;
61  }
62  }
63  } else {
64  // Start at the beginning and work forward
65  for (p = fPFirst; p; p = p->fPNext) {
66  if (p->fType != Html_Block) {
67  --N;
68  if (N == p->fElId) break;
69  }
70  }
71  }
72 
73  return p;
74 }
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// Return the token number for the given TGHtmlElement
78 
80 {
81  //int n = 0;
82 
83  if (!p) return -1;
84  return p->fElId;
85 
86 /// while (p) {
87 /// if (p->fType != Html_Block) ++n;
88 /// p = p->fPPrev;
89 /// }
90 ///
91 /// return n;
92 }
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 /// Find the maximum index for the given token
96 
97 void TGHtml::MaxIndex(TGHtmlElement *p, int *pIndex, int isLast)
98 {
99  if (p == 0) {
100  *pIndex = 0;
101  } else {
102  switch (p->fType) {
103  case Html_Text:
104  *pIndex = p->fCount - isLast;
105  break;
106 
107  case Html_Space:
108  if (p->fStyle.fFlags & STY_Preformatted) {
109  *pIndex = p->fCount - isLast;
110  } else {
111  *pIndex = 0;
112  }
113  break;
114 
115  default:
116  *pIndex = 0;
117  break;
118  }
119  }
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 /// Given a Block and an x coordinate, find the Index of the character
124 /// that is closest to the given x coordinate.
125 ///
126 /// The x-coordinate might specify a point to the left of the block,
127 /// in which case the procedure returns the first token and a character
128 /// index of 0. Or the x-coordinate might specify a point to the right
129 /// of the block, in which case the last token is returned with an index
130 /// equal to its last character.
131 
133  TGHtmlElement **ppToken, int *pIndex)
134 {
135  TGHtmlElement *p;
136  TGFont *font;
137  int len;
138  int n;
139 
140  p = pBlock->fPNext;
141  font = GetFont(p->fStyle.fFont);
142  if (x <= pBlock->fLeft) {
143  *ppToken = p;
144  *pIndex = 0;
145  return;
146  } else if (x >= pBlock->fRight) {
147  *ppToken = p;
148  *pIndex = 0;
149  while (p && p->fType != Html_Block) {
150  *ppToken = p;
151  p = p->fPNext;
152  }
153  p = *ppToken;
154  if (p && p->fType == Html_Text) {
155  *pIndex = p->fCount - 1;
156  }
157  return;
158  }
159  if (pBlock->fN == 0) {
160  *ppToken = p;
161  *pIndex = 0;
162  }
163  n = font->MeasureChars(pBlock->fZ, pBlock->fN, x - pBlock->fLeft, 0, &len);
164  *pIndex = 0;
165  *ppToken = 0;
166  while (p && n >= 0) {
167  switch (p->fType) {
168  case Html_Text:
169  if (n < p->fCount) {
170  *pIndex = n;
171  } else {
172  *pIndex = p->fCount - 1;
173  }
174  *ppToken = p;
175  n -= p->fCount;
176  break;
177 
178  case Html_Space:
179  if (p->fStyle.fFlags & STY_Preformatted) {
180  if (n < p->fCount) {
181  *pIndex = n;
182  } else {
183  *pIndex = p->fCount - 1;
184  }
185  *ppToken = p;
186  n -= p->fCount;
187  } else {
188  *pIndex = 0;
189  *ppToken = p;
190  --n;
191  }
192  break;
193 
194  default:
195  break;
196  }
197  if (p) p = p->fPNext;
198  }
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 /// Convert an Element-based index into a Block-based index.
203 ///
204 /// In other words, given a pointer to an element and an index
205 /// of a particular character within that element, compute a
206 /// pointer to the TGHtmlBlock used to display that character and
207 /// the index in the TGHtmlBlock of the character.
208 
210  TGHtmlBlock **ppBlock, int *piIndex)
211 {
212  int n = sIndex.fI;
213  TGHtmlElement *p;
214 
215  if (sIndex.fP == 0) {
216  *ppBlock = 0;
217  *piIndex = 0;
218  return;
219  }
220  p = sIndex.fP->fPPrev;
221  while (p && p->fType != Html_Block) {
222  switch (p->fType) {
223  case Html_Text:
224  n += p->fCount;
225  break;
226  case Html_Space:
227  if (p->fStyle.fFlags & STY_Preformatted) {
228  n += p->fCount;
229  } else {
230  n++;
231  }
232  break;
233  default:
234  break;
235  }
236  p = p->fPPrev;
237  }
238  if (p) {
239  *ppBlock = (TGHtmlBlock *) p;
240  *piIndex = n;
241  return;
242  }
243  for (p = sIndex.fP; p && p->fType != Html_Block; p = p->fPNext) {}
244  *ppBlock = (TGHtmlBlock *) p;
245  *piIndex = 0;
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 /// Modify an index for both pointer and char +/-/=N
250 
251 int TGHtml::IndexMod(TGHtmlElement **pp, int *ip, char *cp)
252 {
253  char nbuf[50];
254  int i, x, cnt, ccnt[2], cflag[2];
255 
256  if (pp == 0 || !*pp) return -1;
257  ccnt[0] = ccnt[1] = cflag[0] = cflag[1] = 0;
258  x = 0;
259  while (*cp && x < 2) {
260  cnt = 0;
261  i = 1;
262  while (i < 45 && isdigit(cp[i])) {
263  nbuf[i-1] = cp[i];
264  i++;
265  }
266  if (i > 1) {
267  nbuf[i-1] = 0;
268  cnt = atoi(nbuf);
269  if (cnt < 0) return -1;
270  }
271  switch (*cp) {
272  case '+': if (i == 1) ccnt[x] = 1; else ccnt[x] = cnt; break;
273  case '-': if (i == 1) ccnt[x] = -1; else ccnt[x] = -cnt; break;
274  case '=': ccnt[x] = 0; cflag[x] = 1; break;
275  default: return -1;
276  }
277  cp += i;
278  ++x;
279  }
280  if (ccnt[0] > 0) {
281  for (i = 0; i < ccnt[0] && (*pp)->fPNext; ++i) {
282  *pp = (*pp)->fPNext;
283  while ((*pp)->fType == Html_Block && (*pp)->fPNext) {
284  *pp = (*pp)->fPNext;
285  }
286  }
287  } else if (ccnt[0] < 0) {
288  for (i = 0; ccnt[0] < i && (*pp)->fPPrev; --i) {
289  //printf("i=%d, cnt=%d\n", i, ccnt[0]);
290  *pp = (*pp)->fPPrev;
291  while ((*pp)->fType == Html_Block && (*pp)->fPPrev) {
292  *pp = (*pp)->fPPrev;
293  }
294  }
295  }
296  if (ccnt[1] > 0) {
297  for (i = 0; i < ccnt[1]; ++i) (*ip)++;
298  } else if (ccnt[1] < 0) {
299  for (i = 0; i > ccnt[1]; --i) (*ip)--;
300  }
301  return 0;
302 }
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 /// Given a base index name (without any modifiers) return a pointer
306 /// to the token described, and the character within that token.
307 ///
308 /// Valid input forms include:
309 ///
310 /// N.M Token number N (with numbering starting at 1) and
311 /// character number M (with numbering starting at 0).
312 ///
313 /// M.X Like above, but token is markup and X is an attribute.
314 ///
315 /// begin The start of all text
316 ///
317 /// end The end of all text
318 ///
319 /// N.last Last character of token number N.
320 ///
321 /// N.end One past last character of token number N.
322 ///
323 /// sel.first First character of the selection.
324 ///
325 /// sel.last Last character of the selection.
326 ///
327 /// sel.end On past last character of the selection.
328 ///
329 /// insert The character holding the insertion cursor.
330 ///
331 /// @X,Y The character a location X,Y of the clipping window.
332 ///
333 /// &DOM The DOM Address of a token.
334 ///
335 /// Zero is returned if we are successful and non-zero if there is
336 /// any kind of error.
337 ///
338 /// If the given token doesn't exist (for example if there are only 10
339 /// tokens and 11.5 is requested) then *ppToken is left pointing to NULL.
340 /// But the function still returns 0 for success.
341 
342 int TGHtml::DecodeBaseIndex(const char *baseIx,
343  TGHtmlElement **ppToken, int *pIndex)
344 {
345  int i, n, x, y;
346  TGHtmlElement *p = 0;
347  TGHtmlBlock *pBlock;
348  TGHtmlBlock *pNearby;
349  int dist = 1000000;
350  int rc = 0;
351  char buf[200], *base = buf, *suffix, *ep;
352 
353  strlcpy(buf, baseIx, sizeof(buf));
354 
355  while (isspace((unsigned char)*base)) base++;
356  ep = base;
357  while (*ep && !isspace((unsigned char)*ep)) ep++;
358  *ep = 0;
359 
360  if ((suffix = strchr(base, ':'))) *suffix = 0;
361 
362  switch (*base) {
363  case '1': case '2': case '3': case '4': case '5':
364  case '6': case '7': case '8': case '9': case '0':
365  // coverity[secure_coding]
366  n = sscanf(base, "%d.%d", &x, &y);
367  if (n > 0) {
368  p = *ppToken = TokenByIndex(x, 0);
369  }
370  if (n == 2) {
371  *pIndex = y;
372  } else {
373  for (i = 1; isdigit(base[i]); ++i) {}
374  if (base[i] == 0) {
375  *pIndex = 0;
376  } else if (strcmp(&base[i], ".last") == 0) {
377  MaxIndex(p, pIndex, 1);
378  } else if (strcmp(&base[i], ".end") == 0) {
379  MaxIndex(p, pIndex, 0);
380  (*pIndex)++;
381  } else {
382  if (n == 1 && p && p->IsMarkup() && base[i] == '.' &&
383  p->MarkupArg(fZBase + i + 1, 0)) {
384  *pIndex = 0;
385  } else {
386  rc = 1;
387  }
388  }
389  }
390  break;
391 
392  case 'b':
393  if (strcmp(base, "begin") == 0) {
394  p = *ppToken = fPFirst;
395  *pIndex = 0;
396  } else {
397  rc = 1;
398  }
399  break;
400 
401  case 'e':
402  if (strcmp(base, "end") == 0) {
403  p = *ppToken = fPLast;
404  MaxIndex(p, pIndex, 0);
405  } else {
406  rc = 1;
407  }
408  break;
409 
410  case 'l':
411  if (strcmp(base, "last") == 0) {
412  p = *ppToken = fPLast;
413  MaxIndex(p, pIndex, 1);
414  } else {
415  rc = 1;
416  }
417  break;
418 
419  case 's':
420  if (strcmp(base, "sel.first") == 0) {
421  *ppToken = fSelBegin.fP;
422  *pIndex = fSelBegin.fI;
423  } else if (strcmp(base, "sel.last") == 0) {
424  *ppToken = fSelEnd.fP;
425  *pIndex = fSelEnd.fI;
426  } else if (strcmp(base, "sel.end") == 0) {
427  *ppToken = fSelEnd.fP;
428  *pIndex = fSelEnd.fI + 1;
429  } else {
430  rc = 1;
431  }
432  break;
433 
434  case 'i':
435  if (strcmp(baseIx, "insert") == 0) {
436  *ppToken = fIns.fP;
437  *pIndex = fIns.fI;
438  } else {
439  rc = 1;
440  }
441  break;
442 
443 #if 0
444  case '&':
445  *pIndex = 0;
446  if (DomIdLookup("id", base + 1, ppToken)) rc = 1;
447  break;
448 #endif
449 
450  case '@':
451  n = sscanf(base, "@%d,%d", &x, &y);
452  if (n != 2) {
453  rc = 1;
454  break;
455  }
456  x += fVisible.fX;
457  y += fVisible.fY;
458  pNearby = 0;
459  *ppToken = fPLast;
460  *pIndex = 0;
461  for (pBlock = fFirstBlock; pBlock; pBlock = pBlock->fBNext) {
462  int dotest;
463  if (pBlock->fN == 0) {
464  switch (pBlock->fPNext->fType) {
465  case Html_LI:
466  case Html_IMG:
467  case Html_INPUT:
468  case Html_TEXTAREA:
469  case Html_SELECT:
470  dotest = 1;
471  break;
472  default:
473  dotest = 0;
474  break;
475  }
476  } else {
477  dotest = 1;
478  }
479  if (dotest) {
480  if (pBlock->fTop <= y && pBlock->fBottom >= y) {
481  if (pBlock->fLeft > x) {
482  if (pBlock->fLeft - x < dist) {
483  dist = pBlock->fLeft - x;
484  pNearby = pBlock;
485  }
486  } else if (pBlock->fRight < x) {
487  if (x - pBlock->fRight < dist) {
488  dist = x - pBlock->fRight;
489  pNearby = pBlock;
490  }
491  } else {
492  FindIndexInBlock(pBlock, x, ppToken, pIndex);
493  break;
494  }
495  } else {
496  int distY;
497  int distX;
498 
499  if (pBlock->fBottom < y) {
500  distY = y - pBlock->fBottom;
501  } else {
502  distY = pBlock->fTop - y;
503  }
504  if (pBlock->fLeft > x) {
505  distX = pBlock->fLeft - x;
506  } else if (pBlock->fRight < x) {
507  distX = x - pBlock->fRight;
508  } else {
509  distX = 0;
510  }
511  if (distX + 4*distY < dist) {
512  dist = distX + 4*distY;
513  pNearby = pBlock;
514  }
515  }
516  }
517  }
518  if (pBlock == 0) {
519  if (pNearby) {
520  FindIndexInBlock(pNearby, x, ppToken, pIndex);
521  }
522  }
523  break;
524 
525  default:
526  rc = 1;
527  break;
528  }
529  if (suffix) IndexMod(ppToken, pIndex, suffix + 1);
530 
531  return rc;
532 }
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 /// This routine decodes a complete index specification. A complete
536 /// index consists of the base specification followed by modifiers.
537 
538 int TGHtml::GetIndex(const char *zIndex,
539  TGHtmlElement **ppToken, int *pIndex)
540 {
541  return DecodeBaseIndex(zIndex, ppToken, pIndex);
542 }
SHtmlIndex_t fSelBegin
Definition: TGHtml.h:1152
double dist(Rotation3D const &r1, Rotation3D const &r2)
Definition: 3DDistances.cxx:48
char * fZ
Definition: TGHtml.h:720
TGHtmlElement * fP
Definition: TGHtml.h:836
const char * fZBase
Definition: TGHtml.h:1263
int fTop
Definition: TGHtml.h:721
virtual int IsMarkup() const
Definition: TGHtml.h:257
Html_u16_t fRight
Definition: TGHtml.h:722
TGLongPosition fVisible
Definition: TGView.h:58
void MaxIndex(TGHtmlElement *p, int *pIndex, int isLast)
Find the maximum index for the given token.
Definition: TGHtmlIndex.cxx:97
TGHtmlElement * fPLast
Definition: TGHtml.h:1133
#define N
int IndexMod(TGHtmlElement **pp, int *ip, char *cp)
Modify an index for both pointer and char +/-/=N.
TGHtmlBlock * fFirstBlock
Definition: TGHtml.h:1139
virtual TGFont * GetFont(int iFont)
The rendering and layout routines should call this routine in order to get a font structure...
Definition: TGHtml.cxx:1404
int fNToken
Definition: TGHtml.h:1134
#define STY_Preformatted
Definition: TGHtml.h:237
TGHtmlElement * fPNext
Definition: TGHtml.h:265
SHtmlIndex_t fIns
Definition: TGHtml.h:1166
Double_t x[n]
Definition: legend1.C:17
virtual const char * MarkupArg(const char *, const char *)
Definition: TGHtml.h:258
int DecodeBaseIndex(const char *zBase, TGHtmlElement **ppToken, int *pIndex)
Given a base index name (without any modifiers) return a pointer to the token described, and the character within that token.
unsigned int fFont
Definition: TGHtml.h:148
TGHtmlElement * fPPrev
Definition: TGHtml.h:266
TGHtmlBlock * fBNext
Definition: TGHtml.h:724
void IndexToBlockIndex(SHtmlIndex_t sIndex, TGHtmlBlock **ppBlock, int *piIndex)
Convert an Element-based index into a Block-based index.
int GetIndex(const char *zIndex, TGHtmlElement **ppToken, int *pIndex)
This routine decodes a complete index specification.
SHtmlIndex_t fSelEnd
Definition: TGHtml.h:1153
SHtmlStyle_t fStyle
Definition: TGHtml.h:267
void FindIndexInBlock(TGHtmlBlock *pBlock, int x, TGHtmlElement **ppToken, int *pIndex)
Given a Block and an x coordinate, find the Index of the character that is closest to the given x coo...
Html_u16_t fN
Definition: TGHtml.h:723
Html_u8_t fType
Definition: TGHtml.h:268
unsigned int fFlags
Definition: TGHtml.h:154
TGHtmlElement * TokenByIndex(int N, int flag)
Return a pointer to the Nth TGHtmlElement in the list.
Definition: TGHtmlIndex.cxx:48
Definition: TGFont.h:155
Double_t y[n]
Definition: legend1.C:17
TGHtmlElement * fPFirst
Definition: TGHtml.h:1132
int TokenNumber(TGHtmlElement *p)
Return the token number for the given TGHtmlElement.
Definition: TGHtmlIndex.cxx:79
Html_u16_t fLeft
Definition: TGHtml.h:722
Html_16_t fCount
Definition: TGHtml.h:270
int fBottom
Definition: TGHtml.h:721
Int_t MeasureChars(const char *source, Int_t numChars, Int_t maxLength, Int_t flags, Int_t *length) const
Determine the number of characters from the string that will fit in the given horizontal span...
Definition: TGFont.cxx:476
const Int_t n
Definition: legend1.C:16
const char * cnt
Definition: TXMLSetup.cxx:75