// 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;
    }
}
Exemplo n.º 2
0
// 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;
    }
}