Ejemplo n.º 1
0
void
SvgTinter::init()
{
    if ( m_lastPalette != App::instance()->palette() || m_firstRun ) {
        m_tintMap.insert( "#666765", App::instance()->palette().window().color().name() );
        //insert a color for bright ( highlight color )
        m_tintMap.insert( "#66ffff", App::instance()->palette().highlight().color().name() );
        //a slightly lighter than window color:
        m_tintMap.insert( "#e8e8e8", blendColors( App::instance()->palette().window().color(), "#ffffff", 90 ).name() );
        //a slightly darker than window color:
        m_tintMap.insert( "#565755", blendColors( App::instance()->palette().window().color(), "#000000", 90 ).name() );

        //list background:
    #ifdef Q_WS_MAC 
        m_tintMap.insert( "#f0f0f0", blendColors( App::instance()->palette().window().color(), "#000000", 90 ).name() );
        m_tintMap.insert( "#ffffff", blendColors( App::instance()->palette().window().color(), "#000000", 98 ).name() );
    #else
       m_tintMap.insert( "#f0f0f0", App::instance()->palette().base().color().name() );
    #endif

        //alternate list background:
        m_tintMap.insert( "#e0e0e0", App::instance()->palette().alternateBase().color().name() );

        //highlight/window mix:
        m_tintMap.insert( "#123456", blendColors( App::instance()->palette().window().color(), App::instance()->palette().highlight().color().name(), 80 ).name() );

        //text color, useful for adding contrast
        m_tintMap.insert( "#010101", App::instance()->palette().text().color().name() );

        m_lastPalette = App::instance()->palette();
    }
}
Ejemplo n.º 2
0
void GfxPalette::setEGA() {
	int curColor;
	byte color1, color2;

	_sysPalette.colors[1].r  = 0x000; _sysPalette.colors[1].g  = 0x000; _sysPalette.colors[1].b  = 0x0AA;
	_sysPalette.colors[2].r  = 0x000; _sysPalette.colors[2].g  = 0x0AA; _sysPalette.colors[2].b  = 0x000;
	_sysPalette.colors[3].r  = 0x000; _sysPalette.colors[3].g  = 0x0AA; _sysPalette.colors[3].b  = 0x0AA;
	_sysPalette.colors[4].r  = 0x0AA; _sysPalette.colors[4].g  = 0x000; _sysPalette.colors[4].b  = 0x000;
	_sysPalette.colors[5].r  = 0x0AA; _sysPalette.colors[5].g  = 0x000; _sysPalette.colors[5].b  = 0x0AA;
	_sysPalette.colors[6].r  = 0x0AA; _sysPalette.colors[6].g  = 0x055; _sysPalette.colors[6].b  = 0x000;
	_sysPalette.colors[7].r  = 0x0AA; _sysPalette.colors[7].g  = 0x0AA; _sysPalette.colors[7].b  = 0x0AA;
	_sysPalette.colors[8].r  = 0x055; _sysPalette.colors[8].g  = 0x055; _sysPalette.colors[8].b  = 0x055;
	_sysPalette.colors[9].r  = 0x055; _sysPalette.colors[9].g  = 0x055; _sysPalette.colors[9].b  = 0x0FF;
	_sysPalette.colors[10].r = 0x055; _sysPalette.colors[10].g = 0x0FF; _sysPalette.colors[10].b = 0x055;
	_sysPalette.colors[11].r = 0x055; _sysPalette.colors[11].g = 0x0FF; _sysPalette.colors[11].b = 0x0FF;
	_sysPalette.colors[12].r = 0x0FF; _sysPalette.colors[12].g = 0x055; _sysPalette.colors[12].b = 0x055;
	_sysPalette.colors[13].r = 0x0FF; _sysPalette.colors[13].g = 0x055; _sysPalette.colors[13].b = 0x0FF;
	_sysPalette.colors[14].r = 0x0FF; _sysPalette.colors[14].g = 0x0FF; _sysPalette.colors[14].b = 0x055;
	_sysPalette.colors[15].r = 0x0FF; _sysPalette.colors[15].g = 0x0FF; _sysPalette.colors[15].b = 0x0FF;
	for (curColor = 0; curColor <= 15; curColor++) {
		_sysPalette.colors[curColor].used = 1;
	}
	// Now setting colors 16-254 to the correct mix colors that occur when not doing a dithering run on
	//  finished pictures
	for (curColor = 0x10; curColor <= 0xFE; curColor++) {
		_sysPalette.colors[curColor].used = 1;
		color1 = curColor & 0x0F; color2 = curColor >> 4;

		_sysPalette.colors[curColor].r = blendColors(_sysPalette.colors[color1].r, _sysPalette.colors[color2].r);
		_sysPalette.colors[curColor].g = blendColors(_sysPalette.colors[color1].g, _sysPalette.colors[color2].g);
		_sysPalette.colors[curColor].b = blendColors(_sysPalette.colors[color1].b, _sysPalette.colors[color2].b);
	}
	_sysPalette.timestamp = 1;
	setOnScreen();
}
Ejemplo n.º 3
0
/* blended color cycle */
static void ColorCycleBlend (TLN_Palette srcpalette, TLN_Palette dstpalette, struct Strip* strip, int t)
{
	int c;
	int idx0, idx1;
	uint8_t *srcptr0, *srcptr1, *dstptr;

	int t0 = strip->t0;
	int t1 = strip->timer;
	int count = strip->count;
	int steps = strip->pos;

	/* map [t0 - t1] to [0 - 255] */
	int f1 = lerp (t, t0,t1, 0,255);
	int f0 = 255 - f1;

	for (c=0; c<count; c++)
	{
		if (strip->dir)
		{
			idx0 = (c - steps + count) % count;
			idx1 = (c - steps - 1 + count) % count;
		}
		else
		{
			idx0 = (c + steps) % count;
			idx1 = (c + steps + 1) % count;
		}

		srcptr0 = GetPaletteData (srcpalette, strip->first + idx0);
		srcptr1 = GetPaletteData (srcpalette, strip->first + idx1);
		dstptr  = GetPaletteData (dstpalette, strip->first + c);
		blendColors (srcptr0, srcptr1, dstptr, f0, f1);
	}
}
Ejemplo n.º 4
0
sf::Color ColorGradient::sampleColor(float position) const
{
	// Make sure the positions 0 and 1 are set
	assert(mColors.count(0.f) && mColors.count(1.f));

	// Find first entry >= position, return color if entry == position
	auto nextColor = mColors.lower_bound(position);
	if (nextColor->first == position)
		return nextColor->second;

	// Find first entry < position
	auto prevColor = std::prev(nextColor);

	// Interpolate color between 2 entries
	float interpolation = (position - prevColor->first) / (nextColor->first - prevColor->first);
	return blendColors(prevColor->second, nextColor->second, interpolation);
}
Ejemplo n.º 5
0
QColor TimelineColorScheme::frameColor(bool present, bool active) const
{
    QColor color = Qt::transparent;

    if (present && !active) {
        color = m_d->baseColor;
    } else if (present && active) {
        QColor bgColor = qApp->palette().color(QPalette::Base);
        int darkenCoeff = bgColor.value() > 128 ? 130 : 80;
        color = m_d->baseColor.darker(darkenCoeff);
    } else if (!present && active) {
        QColor bgColor = qApp->palette().color(QPalette::Base);
        return blendColors(m_d->baseColor, bgColor, 0.2);
    }

    return color;
}
Ejemplo n.º 6
0
void DialogScene::render()
{
	Renderer::Ref renderer = m_manager->getRenderer();
	CL_Sizef window = renderer->getGCSize();

	// render underlying scene:
	m_topScene->render();

	// fade out a little:
	CL_Rectf rcShadow = m_rcBub; rcShadow.translate(CL_Pointf(5.0f, 5.0f));
	CL_Colorf bubColor = blendColors(getPhraseColor(m_newtype), getPhraseColor(m_oldtype), m_percent);

	CL_Draw::fill(renderer->getGC(), rcShadow, CL_Colorf::black);
	CL_Draw::fill(renderer->getGC(), m_rcBub, bubColor);

	m_layout.draw_layout(renderer->getGC());
}
Ejemplo n.º 7
0
LRESULT SpyFrame::onCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
{
	LPNMLVCUSTOMDRAW plvcd = reinterpret_cast<LPNMLVCUSTOMDRAW>(pnmh);
	
	if (CDDS_PREPAINT == plvcd->nmcd.dwDrawStage)
		return CDRF_NOTIFYITEMDRAW;
		
	if (CDDS_ITEMPREPAINT == plvcd->nmcd.dwDrawStage)
	{
		ClientManagerListener::SearchReply re = (ClientManagerListener::SearchReply)(plvcd->nmcd.lItemlParam);
		
		//check if the file or dir is a dupe, then use the dupesetting color
		if (re == ClientManagerListener::SEARCH_HIT)
			plvcd->clrTextBk = SETTING(DUPE_COLOR);
		else if (re == ClientManagerListener::SEARCH_PARTIAL_HIT)
			//if it's a partial hit, try to use some simple blending
			plvcd->clrTextBk = blendColors(SETTING(DUPE_COLOR), SETTING(BACKGROUND_COLOR));
			
#ifdef FLYLINKDC_USE_LIST_VIEW_MATTRESS
		Colors::alternationBkColor(plvcd); // [+] IRainman
#endif
	}
	return CDRF_DODEFAULT;
}
Ejemplo n.º 8
0
  QColor VQMCSimpleChannelRenderer<ShapeDraw>::
  renderChannel(unsigned camera, unsigned ncameras, 
		const VQMCChannelData& data, 
		const VQMCCameraDataLimits& limits,
		bool clip, QPainter& painter, bool draw_fast)
  {
    QColor background_color = painter.background().color();
    QColor return_color = background_color;
    if(data.fNoDraw)return return_color;
    
    if((!data.fNoData)&&(!data.fSuppress))
      {
	double lim = qMax(fabs(limits.fLimitLo.fValue),
			  fabs(limits.fLimitHi.fValue));
	double x = data.fValue/lim;
	
	if(clip)
	  {
	    if(x>1)x=1;
	    else if(x<-1)x=-1;
	  }

	double radius = 0;

	QColor color = background_color;
	bool found_color = getChannelBaseColor(color, camera, data, limits);
	if((draw_fast)&&(color.alphaF()<1.0))
	  blendColors(1.0-color.alphaF(),color,background_color);
	QBrush brush(color,Qt::SolidPattern);
	
	switch(fValueMode)
	  {
	  case VM_RADIUS:
	    radius = fabs(x);
	    if(x<0)brush.setStyle(Qt::NoBrush);
	    else return_color = color;
	    break;
	  case VM_AREA:
	    radius = sqrt(fabs(x));
	    if(x<0)brush.setStyle(Qt::NoBrush);
	    else return_color = color;
	    break;
	  case VM_ALPHA:
	    if(x>=1)
	      {
		return_color = color;
		radius = 1;
	      }
	    else if(x>0)
	      {
		if(draw_fast)blendColors(x,color,background_color);
		else color.setAlphaF(color.alphaF()*x);
		brush.setColor(color);
		return_color = color;
		radius = 1;
	      }
	    else
	      {
		radius = 0;
	      }
	    break;
	  case VM_COLOR:
	    radius = 1;
	    return_color = color;
	    break;
	  }

	if((found_color)&&(radius>0))
	  {
	    QPen saved_pen = painter.pen();
	    QBrush saved_brush = painter.brush();
	    
	    QPen pen(saved_pen);
	    pen.setWidth(0);
	    if((radius<=1.0)||(!fDrawOutline))pen.setColor(color);
	    else pen.setColor(fOutlineColor);
	    painter.setPen(pen);
	    painter.setBrush(brush);

	    painter.scale(radius,radius);
	    ShapeDraw::draw(camera,ncameras,painter,draw_fast);
	    
	    if((fDrawOutline)&&(radius<=1.0))
	      {
		const qreal rescale = 1.0/radius;
		painter.scale(rescale,rescale);
		pen.setColor(fOutlineColor);
		painter.setPen(pen);
		painter.setBrush(QBrush());
		ShapeDraw::draw(camera,ncameras,painter,draw_fast);
	      }

	    painter.setBrush(saved_brush);
	    painter.setPen(saved_pen);
	  }
	else if(fDrawOutline)
	  {
	    QPen saved_pen = painter.pen();
	    QPen pen = painter.pen();
	    pen.setWidth(0);
	    pen.setColor(fOutlineColor);
	    painter.setPen(pen);
	    ShapeDraw::draw(camera,ncameras,painter,draw_fast);
	    painter.setPen(saved_pen);
	  }
      }
    else if(fDrawOutline)
      {
	QPen saved_pen = painter.pen();
	QPen pen = painter.pen();
	pen.setWidth(0);
	pen.setColor(fOutlineColor);
	painter.setPen(pen);
	ShapeDraw::draw(camera,ncameras,painter,draw_fast);
	painter.setPen(saved_pen);
      }

    return return_color;
  }
Ejemplo n.º 9
0
static QColor blendRoles( QPalette::ColorRole src, QPalette::ColorRole dest, double alpha )
{
	QPalette palette = QApplication::palette();
	return blendColors( palette.color( src ), palette.color( dest ), alpha );
}
Ejemplo n.º 10
0
void TextLayer::recreateTexture(VidgfxContext *gfx)
{
	if(!m_isTexDirty)
		return; // Don't waste any time if it hasn't changed
	m_isTexDirty = false;

	// Delete existing texture if one exists
	if(m_texture != NULL)
		vidgfx_context_destroy_tex(gfx, m_texture);
	m_texture = NULL;

	// Determine texture size. We need to keep in mind that the text in the
	// document might extend outside of the layer's bounds.
	m_document.setTextWidth(m_rect.width());
	QSize size(
		(int)ceilf(m_document.size().width()),
		(int)ceilf(m_document.size().height()));

	if(m_document.isEmpty() || size.isEmpty()) {
		// Nothing to display
		return;
	}

	// Create temporary canvas. We need to be careful here as text is rendered
	// differently on premultiplied vs non-premultiplied pixel formats. On a
	// premultiplied format text is rendered with subpixel rendering enabled
	// while on a non-premultiplied format it is not. As we don't want subpixel
	// rendering we use the standard ARGB32 format.
	QSize imgSize(
		size.width() + m_strokeSize * 2, size.height() + m_strokeSize * 2);
	QImage img(imgSize, QImage::Format_ARGB32);
	img.fill(Qt::transparent);
	QPainter p(&img);
	p.setRenderHint(QPainter::Antialiasing, true);

	// Render text
	//m_document.drawContents(&p);

	// Render stroke
	if(m_strokeSize > 0) {
#define STROKE_TECHNIQUE 0
#if STROKE_TECHNIQUE == 0
		// Technique 0: Use QTextDocument's built-in text outliner
		//quint64 timeStart = App->getUsecSinceExec();

		QTextDocument *outlineDoc = m_document.clone(this);

		QTextCharFormat format;
		QPen pen(m_strokeColor, (double)(m_strokeSize * 2));
		pen.setJoinStyle(Qt::RoundJoin);
		format.setTextOutline(pen);
		QTextCursor cursor(outlineDoc);
		cursor.select(QTextCursor::Document);
		cursor.mergeCharFormat(format);

		// Take into account the stroke offset
		p.translate(m_strokeSize, m_strokeSize);

		//quint64 timePath = App->getUsecSinceExec();
		outlineDoc->drawContents(&p);
		delete outlineDoc;

		//quint64 timeEnd = App->getUsecSinceExec();
		//appLog() << "Path time = " << (timePath - timeStart) << " usec";
		//appLog() << "Render time = " << (timeEnd - timePath) << " usec";
		//appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 1
		// Technique 1: Create a text QPainterPath and stroke it
		quint64 timeStart = App->getUsecSinceExec();

		// Create the path for the text's stroke
		QPainterPath path;
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QPointF pos = layout->position() + line.position();
				pos.ry() += line.ascent();
				//appLog() << pos << ": " << text;
				path.addText(pos, block.charFormat().font(), text);
			}
			block = block.next();
		}

		quint64 timePath = App->getUsecSinceExec();
		path = path.simplified(); // Fixes gaps with large stroke sizes
		quint64 timeSimplify = App->getUsecSinceExec();

		// Render the path
		//p.strokePath(path, QPen(m_strokeColor, m_strokeSize));

		// Convert it to a stroke
		QPainterPathStroker stroker;
		stroker.setWidth(m_strokeSize);
		//stroker.setCurveThreshold(2.0);
		stroker.setJoinStyle(Qt::RoundJoin);
		path = stroker.createStroke(path);

		// Render the path
		p.fillPath(path, m_strokeColor);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Path time = " << (timePath - timeStart) << " usec";
		appLog() << "Simplify time = " << (timeSimplify - timePath) << " usec";
		appLog() << "Render time = " << (timeEnd - timeSimplify) << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 2
		// Technique 2: Similar to technique 1 but do each block separately
		quint64 timeStart = App->getUsecSinceExec();
		quint64 timeTotalSimplify = 0;
		quint64 timeTotalRender = 0;

		// Create the path for the text's stroke
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			// Convert this block to a painter path
			QPainterPath path;
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QPointF pos = layout->position() + line.position() +
					QPointF(m_strokeSize, m_strokeSize);
				pos.ry() += line.ascent();
				//appLog() << pos << ": " << text;
				path.addText(pos, block.charFormat().font(), text);
			}

			// Prevent gaps appearing at larger stroke sizes
			quint64 timeA = App->getUsecSinceExec();
			path = path.simplified();
			quint64 timeB = App->getUsecSinceExec();
			timeTotalSimplify += timeB - timeA;

			// Render the path
			QPen pen(m_strokeColor, m_strokeSize * 2);
			pen.setJoinStyle(Qt::RoundJoin);
			p.strokePath(path, pen);
			timeA = App->getUsecSinceExec();
			timeTotalRender += timeA - timeB;

			// Iterate
			block = block.next();
		}

		// Make the final draw take into account the stroke offset
		p.translate(m_strokeSize, m_strokeSize);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Simplify time = " << timeTotalSimplify << " usec";
		appLog() << "Render time = " << timeTotalRender << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 3
		// Technique 3: Raster brute-force where for each destination pixel
		// we measure the distance to the closest opaque source pixel
		quint64 timeStart = App->getUsecSinceExec();

		// Get bounding region based on text line bounding rects
		QRegion region;
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QRect rect = line.naturalTextRect()
					.translated(layout->position()).toAlignedRect();
				if(rect.isEmpty())
					continue; // Don't add empty rectangles
				rect.adjust(0, 0, 1, 0); // QTextLine is incorrect?
				rect.adjust(
					-m_strokeSize, -m_strokeSize,
					m_strokeSize, m_strokeSize);
				//appLog() << rect;
				region += rect;
			}

			// Iterate
			block = block.next();
		}
		quint64 timeRegion = App->getUsecSinceExec();

#if 0
		// Debug bounding region
		QPainterPath regionPath;
		regionPath.addRegion(region);
		regionPath.setFillRule(Qt::WindingFill);
		p.fillPath(regionPath, QColor(255, 0, 0, 128));
#endif // 0

		// We cannot read and write to the same image at the same time so
		// create a second one. Note that this is not premultiplied.
		QImage imgOut(size, QImage::Format_ARGB32);
		imgOut.fill(Qt::transparent);

		// Do distance calculation. We assume that non-fully transparent
		// pixels are always next to a fully opaque one so if the closest
		// "covered" pixel is not fully opaque then we can use that pixel's
		// opacity to determine the distance to the shape's edge.
		for(int y = 0; y < img.height(); y++) {
			for(int x = 0; x < img.width(); x++) {
				if(!region.contains(QPoint(x, y)))
					continue;
				float dist = getDistance(img, x, y, m_strokeSize);

				// We fake antialiasing by blurring the edge by 1px
				float outEdge = (float)m_strokeSize;
				if(dist >= outEdge)
					continue; // Outside stroke completely
				float opacity = qMin(1.0f, outEdge - dist);
				QColor col = m_strokeColor;
				col.setAlphaF(col.alphaF() * opacity);

				// Blend the stroke so that it appears under the existing
				// pixel data
				QRgb origRgb = img.pixel(x, y);
				QColor origCol(origRgb);
				origCol.setAlpha(qAlpha(origRgb));
				col = blendColors(col, origCol, 1.0f);
				imgOut.setPixel(x, y, col.rgba());
			}
		}
		quint64 timeRender = App->getUsecSinceExec();

		// Swap image data
		p.end();
		img = imgOut;
		p.begin(&img);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Region time = " << (timeRegion - timeStart) << " usec";
		appLog() << "Render time = " << (timeRender - timeRegion) << " usec";
		appLog() << "Swap time = " << (timeEnd - timeRender) << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#endif // STROKE_TECHNIQUE
	}

	// Render text
	m_document.drawContents(&p);

	// Convert the image to a GPU texture
	m_texture = vidgfx_context_new_tex(gfx, img);

	// Preview texture for debugging
	//img.save(App->getDataDirectory().filePath("Preview.png"));
}
Ejemplo n.º 11
0
void BaseEditor::paintEvent(QPaintEvent *e)
{
    //copy from QPlainTextEditor
    QPainter painter(viewport());
    Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(document()->documentLayout()));

    QPointF offset(contentOffset());

    QRect er = e->rect();
    QRect viewportRect = viewport()->rect();

    bool editable = !isReadOnly();

    QTextBlock block = firstVisibleBlock();
    qreal maximumWidth = document()->documentLayout()->documentSize().width();

    //margin
    qreal lineX = 0;
    if (conf->isDisplayRightColumnMargin()) {
        // Don't use QFontMetricsF::averageCharWidth here, due to it returning
        // a fractional size even when this is not supported by the platform.
        lineX = QFontMetricsF(document()->defaultFont()).width(QLatin1Char('X')) * conf->getRightMarginColumn() + offset.x() + 4;

        if (lineX < viewportRect.width()) {
            const QBrush background = QBrush(QColor(239, 239, 239));
            painter.fillRect(QRectF(lineX, er.top(), viewportRect.width() - lineX, er.height()),
                             background);

            const QColor col = (palette().base().color().value() > 128) ? Qt::black : Qt::white;
            const QPen pen = painter.pen();
            painter.setPen(blendColors(background.isOpaque() ? background.color() : palette().base().color(),
                                       col, 32));
            painter.drawLine(QPointF(lineX, er.top()), QPointF(lineX, er.bottom()));
            painter.setPen(pen);
        }
    }

    // Set a brush origin so that the WaveUnderline knows where the wave started
    painter.setBrushOrigin(offset);

    // keep right margin clean from full-width selection
    int maxX = offset.x() + qMax((qreal)viewportRect.width(), maximumWidth)
               - document()->documentMargin();
    er.setRight(qMin(er.right(), maxX));
    painter.setClipRect(er);


    QAbstractTextDocumentLayout::PaintContext context = getPaintContext();

    while (block.isValid()) {

        QRectF r = blockBoundingRect(block).translated(offset);
        QTextLayout *layout = block.layout();

        if (!block.isVisible()) {
            offset.ry() += r.height();
            block = block.next();
            continue;
        }

        if (r.bottom() >= er.top() && r.top() <= er.bottom()) {

            QTextBlockFormat blockFormat = block.blockFormat();

            QBrush bg = blockFormat.background();
            if (bg != Qt::NoBrush) {
                QRectF contentsRect = r;
                contentsRect.setWidth(qMax(r.width(), maximumWidth));
                fillBackground(&painter, contentsRect, bg);
            }


            QVector<QTextLayout::FormatRange> selections;
            int blpos = block.position();
            int bllen = block.length();
            for (int i = 0; i < context.selections.size(); ++i) {
                const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
                const int selStart = range.cursor.selectionStart() - blpos;
                const int selEnd = range.cursor.selectionEnd() - blpos;
                if (selStart < bllen && selEnd > 0
                    && selEnd > selStart) {
                    QTextLayout::FormatRange o;
                    o.start = selStart;
                    o.length = selEnd - selStart;
                    o.format = range.format;
                    selections.append(o);
                } else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
                           && block.contains(range.cursor.position())) {
                    // for full width selections we don't require an actual selection, just
                    // a position to specify the line. that's more convenience in usage.
                    QTextLayout::FormatRange o;
                    QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
                    o.start = l.textStart();
                    o.length = l.textLength();
                    if (o.start + o.length == bllen - 1)
                        ++o.length; // include newline
                    o.format = range.format;
                    selections.append(o);
                }
            }

            bool drawCursor = ((editable || (textInteractionFlags() & Qt::TextSelectableByKeyboard))
                               && context.cursorPosition >= blpos
                               && context.cursorPosition < blpos + bllen);

            bool drawCursorAsBlock = drawCursor && overwriteMode() ;

            if (drawCursorAsBlock) {
                if (context.cursorPosition == blpos + bllen - 1) {
                    drawCursorAsBlock = false;
                } else {
                    QTextLayout::FormatRange o;
                    o.start = context.cursorPosition - blpos;
                    o.length = 1;
                    o.format.setForeground(palette().base());
                    o.format.setBackground(palette().text());
                    selections.append(o);
                }
            }


            layout->draw(&painter, offset, selections, er);
            if ((drawCursor && !drawCursorAsBlock)
                || (editable && context.cursorPosition < -1
                    && !layout->preeditAreaText().isEmpty())) {
                int cpos = context.cursorPosition;
                if (cpos < -1)
                    cpos = layout->preeditAreaPosition() - (cpos + 2);
                else
                    cpos -= blpos;
                layout->drawCursor(&painter, offset, cpos, cursorWidth());
            }
        }

        offset.ry() += r.height();
        if (offset.y() > viewportRect.height())
            break;
        block = block.next();
    }

    if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
        && (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
        painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());
    }
}