// Paint windows in z-order by first collecting the windows // and then painting consecutive layers with the same z-order, // starting with the lowest z-order. // We don't sort because we want to preserve the order of // containment of windows with the same z-order and non-stable // sort could change it. static void PaintWindowsInZOrder(Graphics *g, Control *c) { Vec<CtrlAndOffset> toPaint; WndFilter wndFilter; CtrlAndOffset * coff; Pen debugPen(Color(255, 0, 0), 1); CollectWindowsBreathFirst(c, 0, 0, &wndFilter, &toPaint); size_t paintedCount = 0; int16 lastPaintedZOrder = INT16_MIN; for (;;) { // find which z-order should we paint now int16 minUnpaintedZOrder = INT16_MAX; for (coff = toPaint.IterStart(); coff; coff = toPaint.IterNext()) { int16 zOrder = coff->c->zOrder; if ((zOrder > lastPaintedZOrder) && (zOrder < minUnpaintedZOrder)) minUnpaintedZOrder = zOrder; } for (coff = toPaint.IterStart(); coff; coff = toPaint.IterNext()) { if (minUnpaintedZOrder == coff->c->zOrder) { coff->c->Paint(g, coff->offX, coff->offY); if (IsDebugPaint()) { Rect bbox(coff->offX, coff->offY, coff->c->pos.Width, coff->c->pos.Height); g->DrawRectangle(&debugPen, bbox); } ++paintedCount; } } if (paintedCount == toPaint.Count()) return; CrashIf(paintedCount > toPaint.Count()); lastPaintedZOrder = minUnpaintedZOrder; } }
// TODO: draw link in the appropriate format (blue text, underlined, should show hand cursor when // mouse is over a link. There's a slight complication here: we only get explicit information about // strings, not about the whitespace and we should underline the whitespace as well. Also the text // should be underlined at a baseline void DrawHtmlPage(Graphics* g, mui::ITextRender* textDraw, Vec<DrawInstr>* drawInstructions, REAL offX, REAL offY, bool showBbox, Color textColor, bool* abortCookie) { Pen debugPen(Color(255, 0, 0), 1); // Pen linePen(Color(0, 0, 0), 2.f); Pen linePen(Color(0x5F, 0x4B, 0x32), 2.f); WCHAR buf[512]; // GDI text rendering suffers terribly if we call GetHDC()/ReleaseHDC() around every // draw, so first draw text and then paint everything else textDraw->SetTextColor(textColor); Status status = Ok; Timer t; textDraw->Lock(); for (DrawInstr& i : *drawInstructions) { RectF bbox = i.bbox; bbox.X += offX; bbox.Y += offY; if (InstrString == i.type || InstrRtlString == i.type) { size_t strLen = str::Utf8ToWcharBuf(i.str.s, i.str.len, buf, dimof(buf)); // soft hyphens should not be displayed strLen -= str::RemoveChars(buf, L"\xad"); textDraw->Draw(buf, strLen, bbox, InstrRtlString == i.type); } else if (InstrSetFont == i.type) { textDraw->SetFont(i.font); } if (abortCookie && *abortCookie) break; } textDraw->Unlock(); double dur = t.Stop(); lf("DrawHtmlPage: textDraw %.2f ms", dur); for (DrawInstr& i : *drawInstructions) { RectF bbox = i.bbox; bbox.X += offX; bbox.Y += offY; if (InstrLine == i.type) { // hr is a line drawn in the middle of bounding box REAL y = floorf(bbox.Y + bbox.Height / 2.f + 0.5f); PointF p1(bbox.X, y); PointF p2(bbox.X + bbox.Width, y); if (showBbox) { status = g->DrawRectangle(&debugPen, bbox); CrashIf(status != Ok); } status = g->DrawLine(&linePen, p1, p2); CrashIf(status != Ok); } else if (InstrImage == i.type) { // TODO: cache the bitmap somewhere (?) Bitmap* bmp = BitmapFromData(i.img.data, i.img.len); if (bmp) { status = g->DrawImage(bmp, bbox, 0, 0, (REAL)bmp->GetWidth(), (REAL)bmp->GetHeight(), UnitPixel); // GDI+ sometimes seems to succeed in loading an image because it lazily decodes it CrashIf(status != Ok && status != Win32Error); } delete bmp; } else if (InstrLinkStart == i.type) { // TODO: set text color to blue REAL y = floorf(bbox.Y + bbox.Height + 0.5f); PointF p1(bbox.X, y); PointF p2(bbox.X + bbox.Width, y); Pen linkPen(textColor); status = g->DrawLine(&linkPen, p1, p2); CrashIf(status != Ok); } else if (InstrString == i.type || InstrRtlString == i.type) { if (showBbox) { status = g->DrawRectangle(&debugPen, bbox); CrashIf(status != Ok); } } else if (InstrLinkEnd == i.type) { // TODO: set text color back again } else if ((InstrElasticSpace == i.type) || (InstrFixedSpace == i.type) || (InstrString == i.type) || (InstrRtlString == i.type) || (InstrSetFont == i.type) || (InstrAnchor == i.type)) { // ignore } else { CrashIf(true); } if (abortCookie && *abortCookie) break; } }