// $Id: TGHtmlDraw.cxx,v 1.1 2007/05/04 17:07:01 brun Exp $ // Author: Valeriy Onuchin 03/05/2007 /************************************************************************* * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ /************************************************************************** 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 render HTML onto the screen for the TGHtml widget. #include #include #include "TGHtml.h" #include "TImage.h" //______________________________________________________________________________ TGHtmlBlock::TGHtmlBlock() : TGHtmlElement(Html_Block) { // ctor. fZ = NULL; fTop = fBottom = 0; fLeft = fRight = 0; fN = 0; fPPrev = fPNext = 0; fBPrev = fBNext = 0; } //______________________________________________________________________________ TGHtmlBlock::~TGHtmlBlock() { // dtor. if (fZ) delete[] fZ; } //______________________________________________________________________________ void TGHtml::UnlinkAndFreeBlock(TGHtmlBlock *pBlock) { // Destroy the given Block after first unlinking it from the element list. // Note that this unlinks the block from the element list only -- not from // the block list. if (pBlock->fPNext) { pBlock->fPNext->fPPrev = pBlock->fPPrev; } else { fPLast = pBlock->fPPrev; } if (pBlock->fPPrev) { pBlock->fPPrev->fPNext = pBlock->fPNext; } else { fPFirst = pBlock->fPNext; } pBlock->fPPrev = pBlock->fPNext = 0; delete pBlock; } //______________________________________________________________________________ void TGHtml::AppendBlock(TGHtmlElement *pToken, TGHtmlBlock *pBlock) { // Append a block to the block list and insert the block into the // element list immediately prior to the element given. // // pToken - The token that comes after pBlock // pBlock - The block to be appended pBlock->fPPrev = pToken->fPPrev; pBlock->fPNext = pToken; pBlock->fBPrev = fLastBlock; pBlock->fBNext = 0; if (fLastBlock) { fLastBlock->fBNext = pBlock; } else { fFirstBlock = pBlock; } fLastBlock = pBlock; if (pToken->fPPrev) { pToken->fPPrev->fPNext = (TGHtmlElement *) pBlock; } else { fPFirst = (TGHtmlElement *) pBlock; } pToken->fPPrev = (TGHtmlElement *) pBlock; } //______________________________________________________________________________ static void GetLetterIndex(char *zBuf, int index, int isUpper) { // Print an ordered list index into the given buffer. Use numbering // like this: // // A B C ... Y Z AA BB CC ... ZZ // // Revert to decimal for indices greater than 52. int seed; if (index < 1 || index > 52) { // coverity[secure_coding]: zBuf is large enough for an integer sprintf(zBuf, "%d", index); return; } if (isUpper) { seed = 'A'; } else { seed = 'a'; } index--; if (index < 26) { zBuf[0] = seed + index; zBuf[1] = 0; } else { index -= 26; zBuf[0] = seed + index; zBuf[1] = seed + index; zBuf[2] = 0; } strcat(zBuf, "."); } //______________________________________________________________________________ static void GetRomanIndex(char *zBuf, int index, int isUpper) { // Print an ordered list index into the given buffer. Use roman // numerals. For indices greater than a few thousand, revert to // decimal. int i = 0; UInt_t j; static struct { int value; const char *name; } values[] = { { 1000, "m" }, { 999, "im" }, { 990, "xm" }, { 900, "cm" }, { 500, "d" }, { 499, "id" }, { 490, "xd" }, { 400, "cd" }, { 100, "c" }, { 99, "ic" }, { 90, "xc" }, { 50, "l" }, { 49, "il" }, { 40, "xl" }, { 10, "x" }, { 9, "ix" }, { 5, "v" }, { 4, "iv" }, { 1, "i" }, }; if (index < 1 || index >= 5000) { // coverity[secure_coding]: zBuf is large enough for an integer sprintf(zBuf, "%d", index); return; } for (j = 0; index > 0 && j < sizeof(values)/sizeof(values[0]); j++) { int k; while (index >= values[j].value) { for (k = 0; values[j].name[k]; k++) { zBuf[i++] = values[j].name[k]; } index -= values[j].value; } } zBuf[i] = 0; if (isUpper) { for (i = 0; zBuf[i]; i++) { zBuf[i] += 'A' - 'a'; } } strcat(zBuf, "."); } //______________________________________________________________________________ void TGHtml::DrawSelectionBackground(TGHtmlBlock *pBlock, Drawable_t drawable, int x, int y) { // Draw the selection background for the given block // // x, y - Virtual coords of top-left of drawable int xLeft, xRight; // Left and right bounds of box to draw int yTop, yBottom; // Top and bottom of box TGHtmlElement *p = 0; // First element of the block TGFont *font=0; // Font GContext_t gc; // GC for drawing if (pBlock == 0 || (pBlock->fFlags & HTML_Selected) == 0) return; xLeft = pBlock->fLeft - x; if (pBlock == fPSelStartBlock && fSelStartIndex > 0) { if (fSelStartIndex >= pBlock->fN) return; p = pBlock->fPNext; font = GetFont(p->fStyle.fFont); if (font == 0) return; if (p->fType == Html_Text) { TGHtmlTextElement *tp = (TGHtmlTextElement *) p; xLeft = tp->fX - x + font->TextWidth(pBlock->fZ, fSelStartIndex); } } xRight = pBlock->fRight - x; if (pBlock == fPSelEndBlock && fSelEndIndex < pBlock->fN) { if (p == 0) { p = pBlock->fPNext; font = GetFont(p->fStyle.fFont); if (font == 0) return; } if (p->fType == Html_Text) { TGHtmlTextElement *tp = (TGHtmlTextElement *) p; xRight = tp->fX - x + font->TextWidth(pBlock->fZ, fSelEndIndex); } } yTop = pBlock->fTop - y; yBottom = pBlock->fBottom - y; gc = GetGC(COLOR_Selection, FONT_Any); Int_t xx = xLeft; Int_t yy = yTop; UInt_t width = xRight - xLeft; UInt_t height = yBottom - yTop; gVirtualX->FillRectangle(drawable, gc, xx, yy, width, height); } //______________________________________________________________________________ void TGHtml::DrawRect(Drawable_t drawable, TGHtmlElement *src, int x, int y, int w, int h, int depth, int relief) { // Draw a rectangle. The rectangle will have a 3-D appearance if // flat is 0 and a flat appearance if flat is 1. // // depth - width of the relief or the flat line Int_t xx, yy; UInt_t width, height; if (depth > 0) { int i; GContext_t gcLight, gcDark; if (relief != HTML_RELIEF_FLAT) { int iLight1, iDark1; iLight1 = GetLightShadowColor(src->fStyle.fBgcolor); gcLight = GetGC(iLight1, FONT_Any); iDark1 = GetDarkShadowColor(src->fStyle.fBgcolor); gcDark = GetGC(iDark1, FONT_Any); if (relief == HTML_RELIEF_SUNKEN) { GContext_t gcTemp = gcLight; gcLight = gcDark; gcDark = gcTemp; } } else { gcLight = GetGC(src->fStyle.fColor, FONT_Any); gcDark = gcLight; } xx = x; yy = y; width = depth; height = h; gVirtualX->FillRectangle(drawable, gcLight, xx, yy, width, height); xx = x + w - depth; gVirtualX->FillRectangle(drawable, gcLight, xx, yy, width, height); for (i = 0; i < depth && i < h/2; i++) { gVirtualX->DrawLine(drawable, gcLight, x+i, y+i, x+w-i-1, y+i); gVirtualX->DrawLine(drawable, gcDark, x+i, y+h-i-1, x+w-i-1, y+h-i-1); } } if (h > depth*2 && w > depth*2) { GContext_t gcBg; gcBg = GetGC(src->fStyle.fBgcolor, FONT_Any); xx = x + depth; yy = y + depth; width = w - depth*2; height = h - depth*2; gVirtualX->FillRectangle(drawable, gcBg, xx, yy, width, height); } } //______________________________________________________________________________ void TGHtml::BlockDraw(TGHtmlBlock *pBlock, Drawable_t drawable, int drawableLeft, int drawableTop, int drawableWidth, int drawableHeight, Pixmap_t pixmap) { // Display a single HtmlBlock. This is where all the drawing happens. TGFont *font; // Font to use to render text GContext_t gc; // A graphics context TGHtmlElement *src; // TGHtmlElement holding style information TGHtmlTable *pTable; // The table (when drawing part of a table) Int_t x, y; // Where to draw UInt_t width, height; if (pBlock == 0) return; src = pBlock->fPNext; while (src && (src->fFlags & HTML_Visible) == 0) src = src->fPNext; if (src == 0) return; if (pBlock->fN > 0) { // We must be dealing with plain old text if (src->fType == Html_Text) { TGHtmlTextElement *tsrc = (TGHtmlTextElement *) src; x = tsrc->fX; y = tsrc->fY; } else { CANT_HAPPEN; return; } if (pBlock->fFlags & HTML_Selected) { DrawSelectionBackground(pBlock, drawable, drawableLeft, drawableTop); } gc = GetGC(src->fStyle.fColor, src->fStyle.fFont); font = GetFont(src->fStyle.fFont); if (font == 0) return; font->DrawChars(drawable, gc, pBlock->fZ, pBlock->fN, x - drawableLeft, y - drawableTop); if (src->fStyle.fFlags & STY_Underline) { font->UnderlineChars(drawable, gc, pBlock->fZ, x - drawableLeft, y-drawableTop, 0, pBlock->fN); } if (src->fStyle.fFlags & STY_StrikeThru) { x = pBlock->fLeft - drawableLeft; y = (pBlock->fTop + pBlock->fBottom) / 2 - drawableTop; width = pBlock->fRight - pBlock->fLeft; height = 1 + (pBlock->fBottom - pBlock->fTop > 15); gVirtualX->FillRectangle(drawable, gc, x, y, width, height); } if (pBlock == fPInsBlock && fInsStatus > 0) { if (fInsIndex < pBlock->fN) { TGHtmlTextElement *tsrc = (TGHtmlTextElement *) src; x = tsrc->fX - drawableLeft; x += font->TextWidth(pBlock->fZ, fInsIndex); } else { x = pBlock->fRight - drawableLeft; } if (x > 0) --x; gVirtualX->FillRectangle(drawable, gc, x, pBlock->fTop - drawableTop, 2, pBlock->fBottom - pBlock->fTop); } } else { // We are dealing with a single TGHtmlElement which contains something // other than plain text. int cnt, w; char zBuf[30]; TGHtmlLi *li; TGHtmlImageMarkup *image; switch (src->fType) { case Html_LI: li = (TGHtmlLi *) src; x = li->fX; y = li->fY; switch (li->fLtype) { case LI_TYPE_Enum_1: // coverity[secure_coding]: zBuf is large enough for an int sprintf(zBuf, "%d.", li->fCnt); break; case LI_TYPE_Enum_A: GetLetterIndex(zBuf, li->fCnt, 1); break; case LI_TYPE_Enum_a: GetLetterIndex(zBuf, li->fCnt, 0); break; case LI_TYPE_Enum_I: GetRomanIndex(zBuf, li->fCnt, 1); break; case LI_TYPE_Enum_i: GetRomanIndex(zBuf, li->fCnt, 0); break; default: zBuf[0] = 0; break; } gc = GetGC(src->fStyle.fColor, src->fStyle.fFont); switch (li->fLtype) { case LI_TYPE_Undefined: case LI_TYPE_Bullet1: //gVirtualX->FillArc(drawable, gc, // x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7, // 0, 360*64); break; case LI_TYPE_Bullet2: //gVirtualX->DrawArc(drawable, gc, // x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7, // 0, 360*64); break; case LI_TYPE_Bullet3: gVirtualX->DrawRectangle(drawable, gc, x - 7 - drawableLeft, y - 8 - drawableTop, 7, 7); break; case LI_TYPE_Enum_1: case LI_TYPE_Enum_A: case LI_TYPE_Enum_a: case LI_TYPE_Enum_I: case LI_TYPE_Enum_i: cnt = strlen(zBuf); font = GetFont(src->fStyle.fFont); if (font == 0) return; w = font->TextWidth(zBuf, cnt); font->DrawChars(drawable, gc, zBuf, cnt, x - w - drawableLeft, y - drawableTop); break; } break; case Html_HR: { TGHtmlHr *hr = (TGHtmlHr *) src; int relief = fRuleRelief; switch (relief) { case HTML_RELIEF_RAISED: case HTML_RELIEF_SUNKEN: break; default: relief = HTML_RELIEF_FLAT; break; } DrawRect(drawable, src, hr->fX - drawableLeft, hr->fY - drawableTop, hr->fW, hr->fH, 1, relief); break; } case Html_TABLE: { TGHtmlTable *table = (TGHtmlTable *) src; int relief = fTableRelief; if ((!fBgImage || src->fStyle.fExpbg) && !table->fHasbg) { switch (relief) { case HTML_RELIEF_RAISED: case HTML_RELIEF_SUNKEN: break; default: relief = HTML_RELIEF_FLAT; break; } DrawRect(drawable, src, table->fX - drawableLeft, table->fY - drawableTop, table->fW, table->fH, table->fBorderWidth, relief); } if (table->fBgImage) { DrawTableBgnd(table->fX, table->fY, table->fW, table->fH, pixmap, table->fBgImage); } break; } case Html_TH: case Html_TD: { TGHtmlCell *cell = (TGHtmlCell *) src; int depth, relief; TImage *bgImg; pTable = cell->fPTable; if ((!fBgImage || src->fStyle.fExpbg) && !(pTable && pTable->fHasbg)) { depth = pTable && (pTable->fBorderWidth > 0); switch (fTableRelief) { case HTML_RELIEF_RAISED: relief = HTML_RELIEF_SUNKEN; break; case HTML_RELIEF_SUNKEN: relief = HTML_RELIEF_RAISED; break; default: relief = HTML_RELIEF_FLAT; break; } DrawRect(drawable, src, cell->fX - drawableLeft, cell->fY - drawableTop, cell->fW, cell->fH, depth, relief); } // See if row has an image if (cell->fBgImage) { DrawTableBgnd(cell->fX, cell->fY, cell->fW, cell->fH, pixmap, cell->fBgImage); } else if (cell->fPRow && (bgImg = ((TGHtmlRef *)cell->fPRow)->fBgImage)) { DrawTableBgnd(cell->fX, cell->fY, cell->fW, cell->fH, pixmap, bgImg); } break; } case Html_IMG: image = (TGHtmlImageMarkup *) src; if (image->fPImage) { DrawImage(image, drawable, drawableLeft, drawableTop, drawableLeft + drawableWidth, drawableTop + drawableHeight); } else if (image->fZAlt) { gc = GetGC(src->fStyle.fColor, src->fStyle.fFont); font = GetFont(src->fStyle.fFont); if (font == 0) return; font->DrawChars(drawable, gc, image->fZAlt, strlen(image->fZAlt), image->fX - drawableLeft, image->fY - drawableTop); } break; default: break; } } } //______________________________________________________________________________ void TGHtml::DrawImage(TGHtmlImageMarkup *image, Drawable_t drawable, int drawableLeft, int drawableTop, int drawableRight, int drawableBottom) { // Draw all or part of an image. int imageTop; // virtual canvas coordinate for top of image int x, y; // where to place image on the drawable int imageX, imageY; // \__ Subset of image that fits int imageW, imageH; // / on the drawable imageTop = image->fY - image->fAscent; y = imageTop - drawableTop; if (imageTop + image->fH > drawableBottom) { imageH = drawableBottom - imageTop; } else { imageH = image->fH; } if (y < 0) { imageY = -y; imageH += y; y = 0; } else { imageY = 0; } x = image->fX - drawableLeft; if (image->fX + image->fW > drawableRight) { imageW = drawableRight - image->fX; } else { imageW = image->fW; } if (x < 0) { imageX = -x; imageW += x; x = 0; } else { imageX = 0; } TImage *img = image->fPImage->fImage; imageH = imageH < 0 ? -imageH : imageH; imageW = imageW < 0 ? -imageW : imageW; img->PaintImage(drawable, x, y, imageX, imageY, imageW, imageH); //gVirtualX->Update(kFALSE); image->fRedrawNeeded = 0; } //______________________________________________________________________________ void TGHtml::AnimateImage(TGHtmlImage * /*image*/) { // //TGImage *img = image->image; //if (!img->IsAnimated()) return; //img->NextFrame(); //delete image->timer; //image->timer = new TTimer(this, img->GetAnimDelay()); //ImageChanged(image, image->fW, image->fH); } //______________________________________________________________________________ TGHtmlElement *TGHtml::FillOutBlock(TGHtmlBlock *p) { // Recompute the following fields of the given block structure: // // base.count The number of elements described by this // block structure. // // n The number of characters of text output // associated with this block. If the block // renders something other than text (ex: ) // then set n to 0. // // z Pointer to malloced memory containing the // text associated with this block. NULL if // n is 0. // // Return a pointer to the first TGHtmlElement not covered by the block. TGHtmlElement *pElem; int go, i, n, x, y; SHtmlStyle_t style; char zBuf[2000]; // Reset n and z if (p->fN) p->fN = 0; if (p->fZ) delete[] p->fZ; p->fZ = 0; // Skip over TGHtmlElements that aren't directly displayed. pElem = p->fPNext; p->fCount = 0; while (pElem && (pElem->fFlags & HTML_Visible) == 0) { TGHtmlElement *fPNext = pElem->fPNext; if (pElem->fType == Html_Block) { UnlinkAndFreeBlock((TGHtmlBlock *) pElem); } else { p->fCount++; } pElem = fPNext; } if (pElem == 0) return 0; // Handle "special" elements. if (pElem->fType != Html_Text) { switch (pElem->fType) { case Html_HR: { TGHtmlHr *hr = (TGHtmlHr *) pElem; p->fTop = hr->fY - hr->fH; p->fBottom = hr->fY; p->fLeft = hr->fX; p->fRight = hr->fX + hr->fW; break; } case Html_LI: { TGHtmlLi *li = (TGHtmlLi *) pElem; p->fTop = li->fY - li->fAscent; p->fBottom = li->fY + li->fDescent; p->fLeft = li->fX - 10; p->fRight = li->fX + 10; break; } case Html_TD: case Html_TH: { TGHtmlCell *cell = (TGHtmlCell *) pElem; p->fTop = cell->fY; p->fBottom = cell->fY + cell->fH; p->fLeft = cell->fX; p->fRight = cell->fX + cell->fW; break; } case Html_TABLE: { TGHtmlTable *table = (TGHtmlTable *) pElem; p->fTop = table->fY; p->fBottom = table->fY + table->fH; p->fLeft = table->fX; p->fRight = table->fX + table->fW; break; } case Html_IMG: { TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) pElem; p->fTop = image->fY - image->fAscent; p->fBottom = image->fY + image->fDescent; p->fLeft = image->fX; p->fRight = image->fX + image->fW; break; } } p->fCount++; return pElem->fPNext; } // If we get this far, we must be dealing with text. TGHtmlTextElement *text = (TGHtmlTextElement *) pElem; n = 0; x = text->fX; y = text->fY; p->fTop = y - text->fAscent; p->fBottom = y + text->fDescent; p->fLeft = x; style = pElem->fStyle; go = 1; while (pElem) { TGHtmlElement *fPNext = pElem->fPNext; switch (pElem->fType) { case Html_Text: { TGHtmlTextElement *txt = (TGHtmlTextElement *) pElem; if (pElem->fFlags & STY_Invisible) { break; } if (txt->fSpaceWidth <= 0) { //CANT_HAPPEN; break; } if (y != txt->fY || style.fFont != pElem->fStyle.fFont || style.fColor != pElem->fStyle.fColor || (style.fFlags & STY_FontMask) != (pElem->fStyle.fFlags & STY_FontMask)) { go = 0; } else { int sw = txt->fSpaceWidth; int nSpace = (txt->fX - x) / sw; if (nSpace * sw + x != txt->fX) { go = 0; } else if ((n + nSpace + pElem->fCount) >= (int)sizeof(zBuf)) { // go = 0; - this caused a hang, instead lets do what we can for (i = 0; i < nSpace && (n+1) < (int)sizeof(zBuf); ++i) { zBuf[n++] = ' '; } strncpy(&zBuf[n], txt->fZText, sizeof(zBuf) - n - 1); zBuf[sizeof(zBuf)-1] = 0; n += i; x = txt->fX + txt->fW; } else { for (i = 0; i < nSpace && (n+1) < (int)sizeof(zBuf); ++i) { zBuf[n++] = ' '; } strncpy(&zBuf[n], txt->fZText, sizeof(zBuf) - n - 1); zBuf[sizeof(zBuf)-1] = 0; n += pElem->fCount; x = txt->fX + txt->fW; } } break; } case Html_Space: if (pElem->fStyle.fFont != style.fFont) { pElem = pElem->fPNext; go = 0; } else if ((style.fFlags & STY_Preformatted) != 0 && (pElem->fFlags & HTML_NewLine) != 0) { pElem = pElem->fPNext; go = 0; } break; case Html_Block: UnlinkAndFreeBlock((TGHtmlBlock *) pElem); break; case Html_A: case Html_EndA: go = 0; break; default: if (pElem->fFlags & HTML_Visible) go = 0; break; } if (go == 0) break; p->fCount++; pElem = fPNext; } p->fRight = x; while (n > 0 && zBuf[n-1] == ' ') n--; p->fZ = new char[n+1]; strlcpy(p->fZ, zBuf, n+1); p->fZ[n] = 0; p->fN = n; return pElem; } //______________________________________________________________________________ TGHtmlElement *TGHtml::FindStartOfNextBlock(TGHtmlElement *p, int *pCnt) { // Scan ahead looking for a place to put a block. Return a pointer // to the element which should come immediately after the block. // // if pCnt != 0, then put the number of elements skipped in *pCnt. // // p - First candidate for the start of a block // pCnt - Write number of elements skipped here int cnt = 0; while (p && (p->fFlags & HTML_Visible) == 0) { TGHtmlElement *fPNext = p->fPNext; if (p->fType == Html_Block) { UnlinkAndFreeBlock((TGHtmlBlock *) p); } else { cnt++; } p = fPNext; } if (pCnt) *pCnt = cnt; return p; } //______________________________________________________________________________ void TGHtml::FormBlocks() { // Add additional blocks to the block list in order to cover // all elements on the element list. // // If any old blocks are found on the element list, they must // be left over from a prior rendering. Unlink and delete them. TGHtmlElement *pElem; if (fLastBlock) { pElem = FillOutBlock(fLastBlock); } else { pElem = fPFirst; } while (pElem) { int cnt; pElem = FindStartOfNextBlock(pElem, &cnt); if (pElem) { TGHtmlBlock *pNew = new TGHtmlBlock(); if (fLastBlock) { fLastBlock->fCount += cnt; } AppendBlock(pElem, pNew); pElem = FillOutBlock(pNew); } } } //______________________________________________________________________________ void TGHtml::DrawTableBgnd(int l, int t, int w, int h, Drawable_t pixmap, TImage *image) { // Draw table background //int mx, my, sh, sw, sx, sy, hd; int dl, dt, dr, db, left, top, right, bottom; left = l - fVisible.fX; top = t - fVisible.fY; dl = fDirtyLeft; dt = fDirtyTop; dr = fDirtyRight; db = fDirtyBottom; right = left + w - 1; bottom = top + h - 1; if (dr == 0 && db == 0) { dr = right; db = bottom; } if (left > dr || right < dl || top > db || bottom < dt) return; #if 0 int iw = image->GetWidth(); int ih = image->GetHeight(); if (iw < 4 && ih < 4) return; // CPU burners we ignore. sx = (left + _visibleStart.x) % iw; // X offset within image to start from sw = iw - sx; // Width of section of image to draw. for (mx = left - dl; w > 0; mx += sw, sw = iw, sx = 0) { if (sw > w) sw = w; sy = (top + _visibleStart.y) % ih; // Y offset within image to start from sh = ih - sy; // Height of section of image to draw. for (my = top - dt, hd = h; hd > 0; my += sh, sh = ih, sy = 0) { if (sh > hd) sh = hd; // printf("image: %d %d %d %d %d %d\n", sx, sy, sw, sh, mx,my); image->Draw(pixmap, GetAnyGC(), sx, sy, sw, sh, mx, my); hd -= sh; } w -= sw; } #else if (!image->GetPixmap()) return; GContext_t gc = GetAnyGC(); GCValues_t gcv; // unsigned int mask = kGCTile | kGCFillStyle | // kGCTileStipXOrigin | kGCTileStipYOrigin; gcv.fTile = image->GetPixmap(); gcv.fFillStyle = kFillTiled; gcv.fTsXOrigin = -fVisible.fX - fDirtyLeft; gcv.fTsYOrigin = -fVisible.fY - fDirtyTop; gVirtualX->ChangeGC(gc, &gcv); gVirtualX->FillRectangle(pixmap, gc, left - dl, top - dt, w, h); // mask = kGCFillStyle; gcv.fFillStyle = kFillSolid; gVirtualX->ChangeGC(gc, &gcv); #endif }