00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <ctype.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039
00040 #include "TGHtml.h"
00041
00042
00043
00044 TGHtmlElement *TGHtml::TokenByIndex(int N, int )
00045 {
00046
00047
00048
00049
00050 TGHtmlElement *p;
00051 int n;
00052
00053 if (N == 0) return fPFirst;
00054
00055 if (N > fNToken / 2) {
00056
00057 for (p = fPLast, n = fNToken; p; p = p->fPPrev) {
00058 if (p->fType != Html_Block) {
00059 if (p->fElId == N) break;
00060 --n;
00061 }
00062 }
00063 } else {
00064
00065 for (p = fPFirst; p; p = p->fPNext) {
00066 if (p->fType != Html_Block) {
00067 --N;
00068 if (N == p->fElId) break;
00069 }
00070 }
00071 }
00072
00073 return p;
00074 }
00075
00076
00077 int TGHtml::TokenNumber(TGHtmlElement *p)
00078 {
00079
00080
00081
00082
00083 if (!p) return -1;
00084 return p->fElId;
00085
00086
00087
00088
00089
00090
00091
00092 }
00093
00094
00095 void TGHtml::MaxIndex(TGHtmlElement *p, int *pIndex, int isLast)
00096 {
00097
00098
00099 if (p == 0) {
00100 *pIndex = 0;
00101 } else {
00102 switch (p->fType) {
00103 case Html_Text:
00104 *pIndex = p->fCount - isLast;
00105 break;
00106
00107 case Html_Space:
00108 if (p->fStyle.fFlags & STY_Preformatted) {
00109 *pIndex = p->fCount - isLast;
00110 } else {
00111 *pIndex = 0;
00112 }
00113 break;
00114
00115 default:
00116 *pIndex = 0;
00117 break;
00118 }
00119 }
00120 }
00121
00122
00123 void TGHtml::FindIndexInBlock(TGHtmlBlock *pBlock, int x,
00124 TGHtmlElement **ppToken, int *pIndex)
00125 {
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 TGHtmlElement *p;
00136 TGFont *font;
00137 int len;
00138 int n;
00139
00140 p = pBlock->fPNext;
00141 font = GetFont(p->fStyle.fFont);
00142 if (x <= pBlock->fLeft) {
00143 *ppToken = p;
00144 *pIndex = 0;
00145 return;
00146 } else if (x >= pBlock->fRight) {
00147 *ppToken = p;
00148 *pIndex = 0;
00149 while (p && p->fType != Html_Block) {
00150 *ppToken = p;
00151 p = p->fPNext;
00152 }
00153 p = *ppToken;
00154 if (p && p->fType == Html_Text) {
00155 *pIndex = p->fCount - 1;
00156 }
00157 return;
00158 }
00159 if (pBlock->fN == 0) {
00160 *ppToken = p;
00161 *pIndex = 0;
00162 }
00163 n = font->MeasureChars(pBlock->fZ, pBlock->fN, x - pBlock->fLeft, 0, &len);
00164 *pIndex = 0;
00165 *ppToken = 0;
00166 while (p && n >= 0) {
00167 switch (p->fType) {
00168 case Html_Text:
00169 if (n < p->fCount) {
00170 *pIndex = n;
00171 } else {
00172 *pIndex = p->fCount - 1;
00173 }
00174 *ppToken = p;
00175 n -= p->fCount;
00176 break;
00177
00178 case Html_Space:
00179 if (p->fStyle.fFlags & STY_Preformatted) {
00180 if (n < p->fCount) {
00181 *pIndex = n;
00182 } else {
00183 *pIndex = p->fCount - 1;
00184 }
00185 *ppToken = p;
00186 n -= p->fCount;
00187 } else {
00188 *pIndex = 0;
00189 *ppToken = p;
00190 --n;
00191 }
00192 break;
00193
00194 default:
00195 break;
00196 }
00197 if (p) p = p->fPNext;
00198 }
00199 }
00200
00201
00202 void TGHtml::IndexToBlockIndex(SHtmlIndex_t sIndex,
00203 TGHtmlBlock **ppBlock, int *piIndex)
00204 {
00205
00206
00207
00208
00209
00210
00211
00212 int n = sIndex.fI;
00213 TGHtmlElement *p;
00214
00215 if (sIndex.fP == 0) {
00216 *ppBlock = 0;
00217 *piIndex = 0;
00218 return;
00219 }
00220 p = sIndex.fP->fPPrev;
00221 while (p && p->fType != Html_Block) {
00222 switch (p->fType) {
00223 case Html_Text:
00224 n += p->fCount;
00225 break;
00226 case Html_Space:
00227 if (p->fStyle.fFlags & STY_Preformatted) {
00228 n += p->fCount;
00229 } else {
00230 n++;
00231 }
00232 break;
00233 default:
00234 break;
00235 }
00236 p = p->fPPrev;
00237 }
00238 if (p) {
00239 *ppBlock = (TGHtmlBlock *) p;
00240 *piIndex = n;
00241 return;
00242 }
00243 for (p = sIndex.fP; p && p->fType != Html_Block; p = p->fPNext) {}
00244 *ppBlock = (TGHtmlBlock *) p;
00245 *piIndex = 0;
00246 }
00247
00248
00249 int TGHtml::IndexMod(TGHtmlElement **pp, int *ip, char *cp)
00250 {
00251
00252
00253 char nbuf[50];
00254 int i, x, cnt, ccnt[2], cflag[2];
00255
00256 if (pp == 0 || !*pp) return -1;
00257 ccnt[0] = ccnt[1] = cflag[0] = cflag[1] = 0;
00258 x = 0;
00259 while (*cp && x < 2) {
00260 cnt = 0;
00261 i = 1;
00262 while (i < 45 && isdigit(cp[i])) {
00263 nbuf[i-1] = cp[i];
00264 i++;
00265 }
00266 if (i > 1) {
00267 nbuf[i-1] = 0;
00268 cnt = atoi(nbuf);
00269 if (cnt < 0) return -1;
00270 }
00271 switch (*cp) {
00272 case '+': if (i == 1) ccnt[x] = 1; else ccnt[x] = cnt; break;
00273 case '-': if (i == 1) ccnt[x] = -1; else ccnt[x] = -cnt; break;
00274 case '=': ccnt[x] = 0; cflag[x] = 1; break;
00275 default: return -1;
00276 }
00277 cp += i;
00278 ++x;
00279 }
00280 if (ccnt[0] > 0) {
00281 for (i = 0; i < ccnt[0] && (*pp)->fPNext; ++i) {
00282 *pp = (*pp)->fPNext;
00283 while ((*pp)->fType == Html_Block && (*pp)->fPNext) {
00284 *pp = (*pp)->fPNext;
00285 }
00286 }
00287 } else if (ccnt[0] < 0) {
00288 for (i = 0; ccnt[0] < i && (*pp)->fPPrev; --i) {
00289
00290 *pp = (*pp)->fPPrev;
00291 while ((*pp)->fType == Html_Block && (*pp)->fPPrev) {
00292 *pp = (*pp)->fPPrev;
00293 }
00294 }
00295 }
00296 if (ccnt[1] > 0) {
00297 for (i = 0; i < ccnt[1]; ++i) (*ip)++;
00298 } else if (ccnt[1] < 0) {
00299 for (i = 0; i > ccnt[1]; --i) (*ip)--;
00300 }
00301 return 0;
00302 }
00303
00304
00305 int TGHtml::DecodeBaseIndex(const char *baseIx,
00306 TGHtmlElement **ppToken, int *pIndex)
00307 {
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 int i, n, x, y;
00346 TGHtmlElement *p = 0;
00347 TGHtmlBlock *pBlock;
00348 TGHtmlBlock *pNearby;
00349 int dist = 1000000;
00350 int rc = 0;
00351 char buf[200], *base = buf, *suffix, *ep;
00352
00353 strlcpy(buf, baseIx, sizeof(buf));
00354
00355 while (isspace((unsigned char)*base)) base++;
00356 ep = base;
00357 while (*ep && !isspace((unsigned char)*ep)) ep++;
00358 *ep = 0;
00359
00360 if ((suffix = strchr(base, ':'))) *suffix = 0;
00361
00362 switch (*base) {
00363 case '1': case '2': case '3': case '4': case '5':
00364 case '6': case '7': case '8': case '9': case '0':
00365 n = sscanf(base, "%d.%d", &x, &y);
00366 if (n > 0) {
00367 p = *ppToken = TokenByIndex(x, 0);
00368 }
00369 if (n == 2) {
00370 *pIndex = y;
00371 } else {
00372 for (i = 1; isdigit(base[i]); ++i) {}
00373 if (base[i] == 0) {
00374 *pIndex = 0;
00375 } else if (strcmp(&base[i], ".last") == 0) {
00376 MaxIndex(p, pIndex, 1);
00377 } else if (strcmp(&base[i], ".end") == 0) {
00378 MaxIndex(p, pIndex, 0);
00379 (*pIndex)++;
00380 } else {
00381 if (n == 1 && p && p->IsMarkup() && base[i] == '.' &&
00382 p->MarkupArg(fZBase + i + 1, 0)) {
00383 *pIndex = 0;
00384 } else {
00385 rc = 1;
00386 }
00387 }
00388 }
00389 break;
00390
00391 case 'b':
00392 if (strcmp(base, "begin") == 0) {
00393 p = *ppToken = fPFirst;
00394 *pIndex = 0;
00395 } else {
00396 rc = 1;
00397 }
00398 break;
00399
00400 case 'e':
00401 if (strcmp(base, "end") == 0) {
00402 p = *ppToken = fPLast;
00403 MaxIndex(p, pIndex, 0);
00404 } else {
00405 rc = 1;
00406 }
00407 break;
00408
00409 case 'l':
00410 if (strcmp(base, "last") == 0) {
00411 p = *ppToken = fPLast;
00412 MaxIndex(p, pIndex, 1);
00413 } else {
00414 rc = 1;
00415 }
00416 break;
00417
00418 case 's':
00419 if (strcmp(base, "sel.first") == 0) {
00420 *ppToken = fSelBegin.fP;
00421 *pIndex = fSelBegin.fI;
00422 } else if (strcmp(base, "sel.last") == 0) {
00423 *ppToken = fSelEnd.fP;
00424 *pIndex = fSelEnd.fI;
00425 } else if (strcmp(base, "sel.end") == 0) {
00426 *ppToken = fSelEnd.fP;
00427 *pIndex = fSelEnd.fI + 1;
00428 } else {
00429 rc = 1;
00430 }
00431 break;
00432
00433 case 'i':
00434 if (strcmp(baseIx, "insert") == 0) {
00435 *ppToken = fIns.fP;
00436 *pIndex = fIns.fI;
00437 } else {
00438 rc = 1;
00439 }
00440 break;
00441
00442 #if 0
00443 case '&':
00444 *pIndex = 0;
00445 if (DomIdLookup("id", base + 1, ppToken)) rc = 1;
00446 break;
00447 #endif
00448
00449 case '@':
00450 n = sscanf(base, "@%d,%d", &x, &y);
00451 if (n != 2) {
00452 rc = 1;
00453 break;
00454 }
00455 x += fVisible.fX;
00456 y += fVisible.fY;
00457 pNearby = 0;
00458 *ppToken = fPLast;
00459 *pIndex = 0;
00460 for (pBlock = fFirstBlock; pBlock; pBlock = pBlock->fBNext) {
00461 int dotest;
00462 if (pBlock->fN == 0) {
00463 switch (pBlock->fPNext->fType) {
00464 case Html_LI:
00465 case Html_IMG:
00466 case Html_INPUT:
00467 case Html_TEXTAREA:
00468 case Html_SELECT:
00469 dotest = 1;
00470 break;
00471 default:
00472 dotest = 0;
00473 break;
00474 }
00475 } else {
00476 dotest = 1;
00477 }
00478 if (dotest) {
00479 if (pBlock->fTop <= y && pBlock->fBottom >= y) {
00480 if (pBlock->fLeft > x) {
00481 if (pBlock->fLeft - x < dist) {
00482 dist = pBlock->fLeft - x;
00483 pNearby = pBlock;
00484 }
00485 } else if (pBlock->fRight < x) {
00486 if (x - pBlock->fRight < dist) {
00487 dist = x - pBlock->fRight;
00488 pNearby = pBlock;
00489 }
00490 } else {
00491 FindIndexInBlock(pBlock, x, ppToken, pIndex);
00492 break;
00493 }
00494 } else {
00495 int distY;
00496 int distX;
00497
00498 if (pBlock->fBottom < y) {
00499 distY = y - pBlock->fBottom;
00500 } else {
00501 distY = pBlock->fTop - y;
00502 }
00503 if (pBlock->fLeft > x) {
00504 distX = pBlock->fLeft - x;
00505 } else if (pBlock->fRight < x) {
00506 distX = x - pBlock->fRight;
00507 } else {
00508 distX = 0;
00509 }
00510 if (distX + 4*distY < dist) {
00511 dist = distX + 4*distY;
00512 pNearby = pBlock;
00513 }
00514 }
00515 }
00516 }
00517 if (pBlock == 0) {
00518 if (pNearby) {
00519 FindIndexInBlock(pNearby, x, ppToken, pIndex);
00520 }
00521 }
00522 break;
00523
00524 default:
00525 rc = 1;
00526 break;
00527 }
00528 if (suffix) IndexMod(ppToken, pIndex, suffix + 1);
00529
00530 return rc;
00531 }
00532
00533
00534 int TGHtml::GetIndex(const char *zIndex,
00535 TGHtmlElement **ppToken, int *pIndex)
00536 {
00537
00538
00539
00540 return DecodeBaseIndex(zIndex, ppToken, pIndex);
00541 }