summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-09-12 22:16:33 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-09-12 22:16:33 +0300
commit6f02d2520ff9dc8d98ce0c8d2f554407c2f479fe (patch)
treea9e1d3a1d84978caa1e09ce5e4c4ffad3636b94a /src/ui/documentwidget.c
parent804c677bc9f9a3c89de257a1e6b14be27dea999b (diff)
DocumentWidget: Use VisBuf for buffering
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c196
1 files changed, 144 insertions, 52 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 199b6aa9..edfab0be 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
24#include "scrollwidget.h" 24#include "scrollwidget.h"
25#include "inputwidget.h" 25#include "inputwidget.h"
26#include "labelwidget.h" 26#include "labelwidget.h"
27#include "visbuf.h"
27#include "paint.h" 28#include "paint.h"
28#include "command.h" 29#include "command.h"
29#include "keys.h" 30#include "keys.h"
@@ -38,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
38#include <the_Foundation/objectlist.h> 39#include <the_Foundation/objectlist.h>
39#include <the_Foundation/path.h> 40#include <the_Foundation/path.h>
40#include <the_Foundation/ptrarray.h> 41#include <the_Foundation/ptrarray.h>
42#include <the_Foundation/ptrset.h>
41#include <the_Foundation/regexp.h> 43#include <the_Foundation/regexp.h>
42#include <the_Foundation/stringarray.h> 44#include <the_Foundation/stringarray.h>
43#include <SDL_clipboard.h> 45#include <SDL_clipboard.h>
@@ -126,6 +128,7 @@ void deserialize_Model(iModel *d, iStream *ins) {
126 128
127iDefineTypeConstruction(Model) 129iDefineTypeConstruction(Model)
128 130
131#if 0
129/*----------------------------------------------------------------------------------------------*/ 132/*----------------------------------------------------------------------------------------------*/
130 133
131iDeclareType(VisBuffer) 134iDeclareType(VisBuffer)
@@ -160,7 +163,7 @@ void dealloc_VisBuffer(iVisBuffer *d) {
160} 163}
161 164
162iDefineTypeConstruction(VisBuffer) 165iDefineTypeConstruction(VisBuffer)
163 166#endif
164/*----------------------------------------------------------------------------------------------*/ 167/*----------------------------------------------------------------------------------------------*/
165 168
166static const int smoothSpeed_DocumentWidget_ = 120; /* unit: gap_Text per second */ 169static const int smoothSpeed_DocumentWidget_ = 120; /* unit: gap_Text per second */
@@ -203,7 +206,8 @@ struct Impl_DocumentWidget {
203 int smoothLastOffset; 206 int smoothLastOffset;
204 iBool smoothContinue; 207 iBool smoothContinue;
205 iWidget * menu; 208 iWidget * menu;
206 iVisBuffer * visBuffer; 209 iVisBuf * visBuf;
210 iPtrSet * invalidRuns;
207}; 211};
208 212
209iDefineObjectConstruction(DocumentWidget) 213iDefineObjectConstruction(DocumentWidget)
@@ -238,7 +242,8 @@ void init_DocumentWidget(iDocumentWidget *d) {
238 d->contextLink = NULL; 242 d->contextLink = NULL;
239 d->noHoverWhileScrolling = iFalse; 243 d->noHoverWhileScrolling = iFalse;
240 d->showLinkNumbers = iFalse; 244 d->showLinkNumbers = iFalse;
241 d->visBuffer = new_VisBuffer(); 245 d->visBuf = new_VisBuf();
246 d->invalidRuns = new_PtrSet();
242 init_PtrArray(&d->visibleLinks); 247 init_PtrArray(&d->visibleLinks);
243 init_Click(&d->click, d, SDL_BUTTON_LEFT); 248 init_Click(&d->click, d, SDL_BUTTON_LEFT);
244 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 249 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
@@ -252,7 +257,8 @@ void init_DocumentWidget(iDocumentWidget *d) {
252} 257}
253 258
254void deinit_DocumentWidget(iDocumentWidget *d) { 259void deinit_DocumentWidget(iDocumentWidget *d) {
255 delete_VisBuffer(d->visBuffer); 260 delete_VisBuf(d->visBuf);
261 delete_PtrSet(d->invalidRuns);
256 iRelease(d->media); 262 iRelease(d->media);
257 iRelease(d->request); 263 iRelease(d->request);
258 iRelease(d->doc); 264 iRelease(d->doc);
@@ -365,6 +371,16 @@ static int scrollMax_DocumentWidget_(const iDocumentWidget *d) {
365 (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI; 371 (hasSiteBanner_GmDocument(d->doc) ? 1 : 2) * d->pageMargin * gap_UI;
366} 372}
367 373
374static void invalidateLink_DocumentWidget_(iDocumentWidget *d, iGmLinkId id) {
375 /* A link has multiple runs associated with it. */
376 iConstForEach(PtrArray, i, &d->visibleLinks) {
377 const iGmRun *run = i.ptr;
378 if (run->linkId == id) {
379 insert_PtrSet(d->invalidRuns, run);
380 }
381 }
382}
383
368static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { 384static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) {
369 const iWidget *w = constAs_Widget(d); 385 const iWidget *w = constAs_Widget(d);
370 const iRect docBounds = documentBounds_DocumentWidget_(d); 386 const iRect docBounds = documentBounds_DocumentWidget_(d);
@@ -382,6 +398,12 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) {
382 } 398 }
383 } 399 }
384 if (d->hoverLink != oldHoverLink) { 400 if (d->hoverLink != oldHoverLink) {
401 if (oldHoverLink) {
402 invalidateLink_DocumentWidget_(d, oldHoverLink->linkId);
403 }
404 if (d->hoverLink) {
405 invalidateLink_DocumentWidget_(d, d->hoverLink->linkId);
406 }
385 refresh_Widget(as_Widget(d)); 407 refresh_Widget(as_Widget(d));
386 } 408 }
387 if (isHover_Widget(w) && !contains_Widget(constAs_Widget(d->scroll), mouse)) { 409 if (isHover_Widget(w) && !contains_Widget(constAs_Widget(d->scroll), mouse)) {
@@ -497,7 +519,8 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
497} 519}
498 520
499static void invalidate_DocumentWidget_(iDocumentWidget *d) { 521static void invalidate_DocumentWidget_(iDocumentWidget *d) {
500 iZap(d->visBuffer->validRange); 522 invalidate_VisBuf(d->visBuf);
523 clear_PtrSet(d->invalidRuns);
501} 524}
502 525
503static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { 526static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) {
@@ -1013,23 +1036,16 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *
1013 return iFalse; 1036 return iFalse;
1014} 1037}
1015 1038
1016static void deallocVisBuffer_DocumentWidget_(const iDocumentWidget *d) {
1017 d->visBuffer->size = zero_I2();
1018 iZap(d->visBuffer->validRange);
1019 iForIndices(i, d->visBuffer->texture) {
1020 SDL_DestroyTexture(d->visBuffer->texture[i]);
1021 d->visBuffer->texture[i] = NULL;
1022 }
1023}
1024
1025static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) { 1039static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) {
1026 const iWidget *w = constAs_Widget(d); 1040 const iWidget *w = constAs_Widget(d);
1027 const iBool isVisible = isVisible_Widget(w); 1041 const iBool isVisible = isVisible_Widget(w);
1028 const iInt2 size = bounds_Widget(w).size; 1042 const iInt2 size = bounds_Widget(w).size;
1029 if (!isEqual_I2(size, d->visBuffer->size) || !isVisible) { 1043 if (isVisible) {
1030 dealloc_VisBuffer(d->visBuffer); 1044 alloc_VisBuf(d->visBuf, size, 1);
1031 } 1045 }
1032 if (isVisible && !d->visBuffer->texture[0]) { 1046 else {
1047 dealloc_VisBuf(d->visBuf);
1048#if 0
1033 iZap(d->visBuffer->validRange); 1049 iZap(d->visBuffer->validRange);
1034 d->visBuffer->size = size; 1050 d->visBuffer->size = size;
1035 iAssert(size.x > 0); 1051 iAssert(size.x > 0);
@@ -1042,6 +1058,7 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) {
1042 size.y); 1058 size.y);
1043 SDL_SetTextureBlendMode(d->visBuffer->texture[i], SDL_BLENDMODE_NONE); 1059 SDL_SetTextureBlendMode(d->visBuffer->texture[i], SDL_BLENDMODE_NONE);
1044 } 1060 }
1061#endif
1045 } 1062 }
1046} 1063}
1047 1064
@@ -1067,7 +1084,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1067 } 1084 }
1068 } 1085 }
1069 invalidate_DocumentWidget_(d); 1086 invalidate_DocumentWidget_(d);
1070 deallocVisBuffer_DocumentWidget_(d); 1087 dealloc_VisBuf(d->visBuf);
1071 refresh_Widget(w); 1088 refresh_Widget(w);
1072 updateWindowTitle_DocumentWidget_(d); 1089 updateWindowTitle_DocumentWidget_(d);
1073 } 1090 }
@@ -1568,16 +1585,18 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1568 1585
1569iDeclareType(DrawContext) 1586iDeclareType(DrawContext)
1570 1587
1588#if 0
1571enum iDrawRunPass { 1589enum iDrawRunPass {
1572 static_DrawRunPass, 1590 static_DrawRunPass,
1573 dynamic_DrawRunPass, 1591 dynamic_DrawRunPass,
1574}; 1592};
1593#endif
1575 1594
1576struct Impl_DrawContext { 1595struct Impl_DrawContext {
1577 enum iDrawRunPass pass; 1596// enum iDrawRunPass pass;
1578 const iDocumentWidget *widget; 1597 const iDocumentWidget *widget;
1579 iRect widgetBounds; 1598 iRect widgetBounds;
1580 iRect bounds; /* document area */ 1599 iInt2 viewPos; /* document area origin */
1581 iPaint paint; 1600 iPaint paint;
1582 iBool inSelectMark; 1601 iBool inSelectMark;
1583 iBool inFoundMark; 1602 iBool inFoundMark;
@@ -1607,7 +1626,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol
1607 if (w > width_Rect(run->visBounds) - x) { 1626 if (w > width_Rect(run->visBounds) - x) {
1608 w = width_Rect(run->visBounds) - x; 1627 w = width_Rect(run->visBounds) - x;
1609 } 1628 }
1610 const iInt2 visPos = add_I2(run->bounds.pos, addY_I2(d->bounds.pos, -d->widget->scrollY)); 1629 const iInt2 visPos = add_I2(run->bounds.pos, addY_I2(d->viewPos, -d->widget->scrollY));
1611 fillRect_Paint(&d->paint, (iRect){ addX_I2(visPos, x), 1630 fillRect_Paint(&d->paint, (iRect){ addX_I2(visPos, x),
1612 init_I2(w, height_Rect(run->bounds)) }, color); 1631 init_I2(w, height_Rect(run->bounds)) }, color);
1613 } 1632 }
@@ -1615,9 +1634,9 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol
1615 1634
1616static void drawRun_DrawContext_(void *context, const iGmRun *run) { 1635static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1617 iDrawContext *d = context; 1636 iDrawContext *d = context;
1618 const iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY); 1637 const iInt2 origin = d->viewPos; //addY_I2(d->bounds.pos, -d->widget->scrollY);
1619 if (run->imageId) { 1638 if (run->imageId) {
1620 if (d->pass == static_DrawRunPass) { 1639 /*if (d->pass == static_DrawRunPass)*/ {
1621 SDL_Texture *tex = imageTexture_GmDocument(d->widget->doc, run->imageId); 1640 SDL_Texture *tex = imageTexture_GmDocument(d->widget->doc, run->imageId);
1622 if (tex) { 1641 if (tex) {
1623 const iRect dst = moved_Rect(run->visBounds, origin); 1642 const iRect dst = moved_Rect(run->visBounds, origin);
@@ -1627,8 +1646,9 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1627 } 1646 }
1628 return; 1647 return;
1629 } 1648 }
1649#if 0
1630 /* Text markers. */ 1650 /* Text markers. */
1631 if (d->pass == dynamic_DrawRunPass) { 1651 /*if (d->pass == dynamic_DrawRunPass)*/ {
1632 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), 1652 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()),
1633 isDark_ColorTheme(colorTheme_App()) ? SDL_BLENDMODE_ADD 1653 isDark_ColorTheme(colorTheme_App()) ? SDL_BLENDMODE_ADD
1634 : SDL_BLENDMODE_BLEND); 1654 : SDL_BLENDMODE_BLEND);
@@ -1636,17 +1656,26 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1636 fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); 1656 fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark);
1637 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); 1657 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE);
1638 } 1658 }
1659#endif
1639 enum iColorId fg = run->color; 1660 enum iColorId fg = run->color;
1640 const iGmDocument *doc = d->widget->doc; 1661 const iGmDocument *doc = d->widget->doc;
1641 /* Matches the current drawing pass? */ 1662 /* Matches the current drawing pass? */
1642 const iBool isDynamic = (run->linkId && ~run->flags & decoration_GmRunFlag); 1663// const iBool isDynamic = (run->linkId && ~run->flags & decoration_GmRunFlag);
1643 if (isDynamic ^ (d->pass == dynamic_DrawRunPass)) { 1664// if (isDynamic ^ (d->pass == dynamic_DrawRunPass)) {
1644 return; 1665// return;
1645 } 1666// }
1646 const iBool isHover = 1667 const iBool isHover =
1647 (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId && 1668 (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId &&
1648 ~run->flags & decoration_GmRunFlag); 1669 ~run->flags & decoration_GmRunFlag);
1649 const iInt2 visPos = add_I2(run->visBounds.pos, origin); 1670 const iInt2 visPos = add_I2(run->visBounds.pos, origin);
1671 fillRect_Paint(&d->paint,
1672 (iRect){ visPos,
1673 /* Links have additional hover info on the right side. */
1674 init_I2(run->linkId && ~run->flags & decoration_GmRunFlag
1675 ? d->widgetBounds.size.x - visPos.x
1676 : run->visBounds.size.x,
1677 run->visBounds.size.y) },
1678 tmBackground_ColorId);
1650 if (run->linkId && ~run->flags & decoration_GmRunFlag) { 1679 if (run->linkId && ~run->flags & decoration_GmRunFlag) {
1651 fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart); 1680 fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart);
1652 if (linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) { 1681 if (linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) {
@@ -1654,7 +1683,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1654 } 1683 }
1655 } 1684 }
1656 if (run->flags & siteBanner_GmRunFlag) { 1685 if (run->flags & siteBanner_GmRunFlag) {
1657 if (d->pass == static_DrawRunPass) { 1686 /*if (d->pass == static_DrawRunPass)*/ {
1658 /* Draw the site banner. */ 1687 /* Draw the site banner. */
1659 fillRect_Paint( 1688 fillRect_Paint(
1660 &d->paint, 1689 &d->paint,
@@ -1697,7 +1726,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1697 if (ord < 9 + 26) { 1726 if (ord < 9 + 26) {
1698 const iChar ordChar = ord < 9 ? 0x278a + ord : (0x24b6 + ord - 9); 1727 const iChar ordChar = ord < 9 ? 0x278a + ord : (0x24b6 + ord - 9);
1699 drawString_Text(run->font, 1728 drawString_Text(run->font,
1700 init_I2(left_Rect(d->bounds) - gap_UI / 3, visPos.y), 1729 init_I2(d->viewPos.x - gap_UI / 3, visPos.y),
1701 fg, 1730 fg,
1702 collect_String(newUnicodeN_String(&ordChar, 1))); 1731 collect_String(newUnicodeN_String(&ordChar, 1)));
1703 goto runDrawn; 1732 goto runDrawn;
@@ -1708,7 +1737,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1708 runDrawn:; 1737 runDrawn:;
1709 } 1738 }
1710 /* Presentation of links. */ 1739 /* Presentation of links. */
1711 if (run->linkId && ~run->flags & decoration_GmRunFlag && d->pass == dynamic_DrawRunPass) { 1740 if (run->linkId && ~run->flags & decoration_GmRunFlag/* && d->pass == dynamic_DrawRunPass*/) {
1712 const int metaFont = paragraph_FontId; 1741 const int metaFont = paragraph_FontId;
1713 /* TODO: Show status of an ongoing media request. */ 1742 /* TODO: Show status of an ongoing media request. */
1714 const int flags = linkFlags_GmDocument(doc, run->linkId); 1743 const int flags = linkFlags_GmDocument(doc, run->linkId);
@@ -1819,32 +1848,78 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1819static void draw_DocumentWidget_(const iDocumentWidget *d) { 1848static void draw_DocumentWidget_(const iDocumentWidget *d) {
1820 const iWidget *w = constAs_Widget(d); 1849 const iWidget *w = constAs_Widget(d);
1821 const iRect bounds = bounds_Widget(w); 1850 const iRect bounds = bounds_Widget(w);
1822 const iInt2 origin = topLeft_Rect(bounds); 1851// const iInt2 origin = topLeft_Rect(bounds);
1823 const iRangei visRange = visibleRange_DocumentWidget_(d); 1852 //const iRangei visRange = visibleRange_DocumentWidget_(d);
1824 iVisBuffer * visBuf = d->visBuffer; /* this may be updated/modified here */ 1853 iVisBuf * visBuf = d->visBuf; /* will be updated now */
1825 draw_Widget(w); 1854 draw_Widget(w);
1826 allocVisBuffer_DocumentWidget_(d); 1855 allocVisBuffer_DocumentWidget_(d);
1827 iDrawContext ctxDynamic = { 1856 const iRect ctxWidgetBounds = init_Rect(
1828 .pass = dynamic_DrawRunPass, 1857 0, 0, width_Rect(bounds) - constAs_Widget(d->scroll)->rect.size.x, height_Rect(bounds));
1858// adjusted_Rect(bounds, zero_I2(), init_I2(-constAs_Widget(d->scroll)->rect.size.x, 0)),
1859// neg_I2(origin)); /* omit scrollbar width */
1860 const iRect docBounds = documentBounds_DocumentWidget_(d);
1861// const iRect ctxBounds = moved_Rect(documentBounds_DocumentWidget_(d), neg_I2(origin));
1862 iDrawContext ctx = {
1863// .pass = dynamic_DrawRunPass,
1829 .widget = d, 1864 .widget = d,
1830 .widgetBounds = adjusted_Rect(bounds,
1831 zero_I2(),
1832 init_I2(-constAs_Widget(d->scroll)->rect.size.x, 0)), /* omit scrollbar width */
1833 .bounds = documentBounds_DocumentWidget_(d),
1834 .showLinkNumbers = d->showLinkNumbers, 1865 .showLinkNumbers = d->showLinkNumbers,
1835 }; 1866 };
1836 iDrawContext ctxStatic = ctxDynamic; 1867// iDrawContext ctxStatic = ctxDynamic;
1837 ctxStatic.pass = static_DrawRunPass; 1868// ctxStatic.pass = static_DrawRunPass;
1838 subv_I2(&ctxStatic.widgetBounds.pos, origin); 1869// subv_I2(&ctx.widgetBounds.pos, origin);
1839 subv_I2(&ctxStatic.bounds.pos, origin); 1870// subv_I2(&ctx.bounds.pos, origin);
1840 SDL_Renderer *render = get_Window()->render; 1871// SDL_Renderer *render = get_Window()->render;
1841 /* Static content. */ { 1872 /* Currently visible region. */
1842 iPaint *p = &ctxStatic.paint; 1873 const iRangei vis = visibleRange_DocumentWidget_(d);
1874 const iRangei full = { 0, size_GmDocument(d->doc).y };
1875 reposition_VisBuf(visBuf, vis);
1876 iRangei invalidRange[3];
1877 invalidRanges_VisBuf(visBuf, full, invalidRange);
1878 /* Redraw the invalid ranges. */ {
1879 iPaint *p = &ctx.paint;
1843 init_Paint(p); 1880 init_Paint(p);
1844 const int vbSrc = visBuf->index; 1881// const int vbSrc = visBuf->index;
1845 const int vbDst = visBuf->index ^ 1; 1882// const int vbDst = visBuf->index ^ 1;
1846 iRangei drawRange = visRange; 1883// iRangei drawRange = visRange;
1847 iAssert(visBuf->texture[vbDst]); 1884 iForIndices(i, visBuf->buffers) {
1885 iBool isTargetSet = iFalse;
1886 iVisBufTexture *buf = &visBuf->buffers[i];
1887 ctx.widgetBounds = moved_Rect(ctxWidgetBounds, init_I2(0, -buf->origin));
1888 ctx.viewPos = init_I2(left_Rect(docBounds) - left_Rect(bounds), -buf->origin);
1889 if (!isEmpty_Rangei(invalidRange[i])) {
1890 if (!isTargetSet) {
1891 beginTarget_Paint(p, buf->texture);
1892 isTargetSet = iTrue;
1893 }
1894 if (isEmpty_Rangei(buf->validRange)) {
1895 fillRect_Paint(p, (iRect){ zero_I2(), visBuf->texSize }, tmBackground_ColorId);
1896 }
1897 render_GmDocument(d->doc, invalidRange[i], drawRun_DrawContext_, &ctx);
1898 }
1899 /* Draw any invalidated runs that fall within this buffer. */
1900 const iRangei bufRange = { buf->origin, buf->origin + visBuf->texSize.y };
1901 iConstForEach(PtrSet, r, d->invalidRuns) {
1902 const iGmRun *run = *r.value;
1903 if (!isEmpty_Rangei(intersect_Rangei(
1904 bufRange,
1905 (iRangei){ top_Rect(run->visBounds), bottom_Rect(run->visBounds) }))) {
1906 if (!isTargetSet) {
1907 beginTarget_Paint(p, buf->texture);
1908 isTargetSet = iTrue;
1909 }
1910 drawRun_DrawContext_(&ctx, run);
1911 }
1912 }
1913 if (isTargetSet) {
1914 endTarget_Paint(&ctx.paint);
1915 }
1916 fflush(stdout);
1917 }
1918 validate_VisBuf(visBuf);
1919 clear_PtrSet(d->invalidRuns);
1920 }
1921#if 0
1922// iAssert(visBuf->texture[vbDst]);
1848 beginTarget_Paint(p, visBuf->texture[vbDst]); 1923 beginTarget_Paint(p, visBuf->texture[vbDst]);
1849 const iRect visBufferRect = { zero_I2(), visBuf->size }; 1924 const iRect visBufferRect = { zero_I2(), visBuf->size };
1850 iRect drawRect = visBufferRect; 1925 iRect drawRect = visBufferRect;
@@ -1897,7 +1972,24 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
1897 unsetClip_Paint(p); 1972 unsetClip_Paint(p);
1898 enableKerning_Text = iTrue; 1973 enableKerning_Text = iTrue;
1899 } 1974 }
1900 1975#endif
1976 setClip_Paint(&ctx.paint, bounds);
1977 const int yTop = docBounds.pos.y - d->scrollY;
1978 draw_VisBuf(visBuf, init_I2(bounds.pos.x, yTop));
1979 unsetClip_Paint(&ctx.paint);
1980 /* Fill the top and bottom, in case the document is short. */
1981 if (yTop > top_Rect(bounds)) {
1982 fillRect_Paint(&ctx.paint,
1983 (iRect){ bounds.pos, init_I2(bounds.size.x, yTop - top_Rect(bounds)) },
1984 hasSiteBanner_GmDocument(d->doc) ? tmBannerBackground_ColorId
1985 : tmBackground_ColorId);
1986 }
1987 const int yBottom = yTop + size_GmDocument(d->doc).y;
1988 if (yBottom < bottom_Rect(bounds)) {
1989 fillRect_Paint(&ctx.paint,
1990 init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom),
1991 tmBackground_ColorId);
1992 }
1901// drawRect_Paint(&ctx.paint, 1993// drawRect_Paint(&ctx.paint,
1902// moved_Rect((iRect){ zero_I2(), size_GmDocument(d->doc) }, 1994// moved_Rect((iRect){ zero_I2(), size_GmDocument(d->doc) },
1903// add_I2(topLeft_Rect(ctx.bounds), init_I2(0, -d->scrollY))), 1995// add_I2(topLeft_Rect(ctx.bounds), init_I2(0, -d->scrollY))),