Exemple #1
0
    void
DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len,
	int x, int y, int w, int h, int cellWidth, COLORREF color)
{
    HRESULT hr = S_OK;
    IDWriteBitmapRenderTarget *bmpRT = NULL;

    // Skip when any fonts are not set.
    if (mTextFormat == NULL)
	return;

    // Check possibility of zero divided error.
    if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
	return;

    if (SUCCEEDED(hr))
	hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT);

    if (SUCCEEDED(hr))
    {
	IDWriteTextLayout *textLayout = NULL;

	HDC memdc = bmpRT->GetMemoryDC();
	BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY);

	hr = mDWriteFactory->CreateGdiCompatibleTextLayout(
		text, len, mTextFormat, PixelsToDipsX(w),
		PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout);

	if (SUCCEEDED(hr))
	{
	    DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len };
	    textLayout->SetFontWeight(mFontWeight, textRange);
	    textLayout->SetFontStyle(mFontStyle, textRange);
	}

	if (SUCCEEDED(hr))
	{
	    GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT,
		    mRenderingParams);
	    GdiTextRendererContext data = {
		color,
		PixelsToDipsX(cellWidth),
		0.0f
	    };
	    textLayout->Draw(&data, renderer, 0, 0);
	    SafeRelease(&renderer);
	}

	BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY);

	SafeRelease(&textLayout);
    }

    SafeRelease(&bmpRT);
}
    void addAttributedRange (const AttributedString::Attribute& attr, IDWriteTextLayout& textLayout,
                             const int textLen, ID2D1RenderTarget& renderTarget, IDWriteFontCollection& fontCollection)
    {
        DWRITE_TEXT_RANGE range;
        range.startPosition = attr.range.getStart();
        range.length = jmin (attr.range.getLength(), textLen - attr.range.getStart());

        if (const Font* const font = attr.getFont())
        {
            const String familyName (FontStyleHelpers::getConcreteFamilyName (*font));

            BOOL fontFound = false;
            uint32 fontIndex;
            fontCollection.FindFamilyName (familyName.toWideCharPointer(), &fontIndex, &fontFound);

            if (! fontFound)
                fontIndex = 0;

            ComSmartPtr<IDWriteFontFamily> fontFamily;
            HRESULT hr = fontCollection.GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress());

            ComSmartPtr<IDWriteFont> dwFont;
            uint32 fontFacesCount = 0;
            fontFacesCount = fontFamily->GetFontCount();

            for (int i = fontFacesCount; --i >= 0;)
            {
                hr = fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());

                if (font->getTypefaceStyle() == getFontFaceName (dwFont))
                    break;
            }

            textLayout.SetFontFamilyName (familyName.toWideCharPointer(), range);
            textLayout.SetFontWeight (dwFont->GetWeight(), range);
            textLayout.SetFontStretch (dwFont->GetStretch(), range);
            textLayout.SetFontStyle (dwFont->GetStyle(), range);

            const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);
            textLayout.SetFontSize (font->getHeight() * fontHeightToEmSizeFactor, range);
        }

        if (const Colour* const colour = attr.getColour())
        {
            ComSmartPtr<ID2D1SolidColorBrush> d2dBrush;
            renderTarget.CreateSolidColorBrush (D2D1::ColorF (colour->getFloatRed(),
                                                              colour->getFloatGreen(),
                                                              colour->getFloatBlue(),
                                                              colour->getFloatAlpha()),
                                                d2dBrush.resetAndGetPointerAddress());

            // We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours
            textLayout.SetDrawingEffect (d2dBrush, range);
        }
    }
int nf_print(void * bitmap, uint16_t w, uint16_t h,
	nf_font_t font, nf_feature_t * features, size_t features_count,
	nf_aabb_t * result_rect, const char * text, ...)
{
	if(!bitmap)
	{
		NF_ERROR("can't print with invalid bitmap\n");
		return -1;
	}

	if(!font)
	{
		NF_ERROR("can't print with invalid font\n");
		return -1;
	}

	if(!text)
	{
		NF_ERROR("can't print with invalid text\n");
		return -1;
	}

	// figure out text rendering settings
	HRESULT hr = 0;
	D2D1_COLOR_F bg_color = D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f);
	D2D1_COLOR_F fg_color = D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f);
	DWRITE_WORD_WRAPPING text_wrap = DWRITE_WORD_WRAPPING_WRAP;
	DWRITE_TEXT_ALIGNMENT text_alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
	DWRITE_PARAGRAPH_ALIGNMENT parg_alignment = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
	D2D1_TEXT_ANTIALIAS_MODE text_aa_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
	float ppi_x = 0.0f, ppi_y = 0.0f;

	ctx.d2d_factory->GetDesktopDpi(&ppi_x, &ppi_y);

	size_t len = strlen(text) + 1;
	WCHAR * wtext = (WCHAR*)alloca(len * sizeof(WCHAR));
	size_t wlen = mbstowcs(wtext, text, len);
	if(wlen == (size_t)-1)
	{
		NF_ERROR("failed to convert text to wchar, text : '%s'\n", text);
		return -1;
	}

	IDWriteTextLayout * layout = NULL;
	if(FAILED(hr = ctx.dw_factory->CreateTextLayout(
					wtext, wlen,
					(IDWriteTextFormat*)font,
					w, h,
					&layout)))
	{
		nf_explain_hr(hr, "can't create dwrite text layout");
		return -1;
	}

	for(size_t i = 0; i < features_count; ++i)
	{
		DWRITE_TEXT_RANGE range;
		range.startPosition = features[i].range.start;
		range.length = features[i].range.end - features[i].range.start + 1;

		switch(features[i].type)
		{
		case NF_FEATURE_BOLD:
			layout->SetFontWeight(DWRITE_FONT_WEIGHT_BOLD, range);
			break;
		case NF_FEATURE_UNDERLINE:
			layout->SetUnderline(true, range);
			break;
		case NF_FEATURE_ITALIC:
			layout->SetFontStyle(DWRITE_FONT_STYLE_ITALIC, range);
			break;
		case NF_FEATURE_WRAP:
			text_wrap = DWRITE_WORD_WRAPPING_WRAP;
			break;
		case NF_FEATURE_NO_WRAP:
			text_wrap = DWRITE_WORD_WRAPPING_NO_WRAP;
			break;
		case NF_FEATURE_ALIGN_LEFT:
			text_alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
			break;
		case NF_FEATURE_ALIGN_CENTER:
			text_alignment = DWRITE_TEXT_ALIGNMENT_CENTER;
			break;
		case NF_FEATURE_ALIGN_RIGHT:
			text_alignment = DWRITE_TEXT_ALIGNMENT_TRAILING;
			break;
		case NF_FEATURE_ALIGN_JUSTIFIED:
			text_alignment = DWRITE_TEXT_ALIGNMENT_JUSTIFIED;
			break;
		case NF_FEATURE_ALIGN_PARAGRAPH_LEFT:
			parg_alignment = DWRITE_PARAGRAPH_ALIGNMENT_NEAR;
			break;
		case NF_FEATURE_ALIGN_PARAGRAPH_CENTER:
			parg_alignment = DWRITE_PARAGRAPH_ALIGNMENT_CENTER;
			break;
		case NF_FEATURE_ALIGN_PARAGRAPH_RIGHT:
			parg_alignment = DWRITE_PARAGRAPH_ALIGNMENT_FAR;
			break;
		case NF_FEATURE_AA_DISABLED:
			text_aa_mode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
			break;
		case NF_FEATURE_AA_WIN_CLEARTYPE:
			text_aa_mode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
			break;
		case NF_FEATURE_AA_WIN_GREYSCALE:
			text_aa_mode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
			break;
		case NF_FEATURE_PPI:
			ppi_x = features[i].ppi.x;
			ppi_y = features[i].ppi.y;
			break;
		case NF_FEATURE_COLOR_BG:
			bg_color = D2D1::ColorF(
				features[i].color.r,
				features[i].color.g,
				features[i].color.b,
				features[i].color.a);
			break;
		case NF_FEATURE_COLOR_TEXT:
			fg_color = D2D1::ColorF(
				features[i].color.r,
				features[i].color.g,
				features[i].color.b,
				features[i].color.a);
			break;
		default:
			break;
		}
	}

	layout->SetWordWrapping(text_wrap);
	layout->SetTextAlignment(text_alignment);
	layout->SetParagraphAlignment(parg_alignment);
	ctx.d2d_rt->SetDpi(ppi_x, ppi_y);
	ctx.d2d_rt->SetTextAntialiasMode(text_aa_mode);
	ctx.d2d_brush->SetColor(fg_color);

	// figure our result metrics
	// TODO does this call actually rasterizes text?
	DWRITE_TEXT_METRICS text_metrics;
	layout->GetMetrics(&text_metrics);
	float clip_x1 = text_metrics.left;
	float clip_y1 = text_metrics.top;
	float clip_x2 = text_metrics.left + text_metrics.width;
	float clip_y2 = text_metrics.top + text_metrics.height;
	clip_x1 = clip_x1 < 0 ? 0 : (clip_x1 >= w ? w - 1 : clip_x1);
	clip_y1 = clip_y1 < 0 ? 0 : (clip_y1 >= h ? h - 1 : clip_y1);
	clip_x2 = clip_x2 < 0 ? 0 : (clip_x2 >= w ? w - 1 : clip_x2);
	clip_y2 = clip_y2 < 0 ? 0 : (clip_y2 >= h ? h - 1 : clip_y2);
	float clip_w = clip_x2 - clip_x1 + 1.0f;
	float clip_h = clip_y2 - clip_y1 + 1.0f;
	nf_aabb_t aabb;
	aabb.x = clip_x1;
	aabb.y = clip_y1;
	aabb.w = clip_w;
	aabb.h = clip_h;
	if(result_rect)
		*result_rect = aabb;

	// render text
	ctx.d2d_rt->BeginDraw();
	ctx.d2d_rt->Clear(bg_color);
	ctx.d2d_rt->DrawTextLayout(D2D1::Point2F(), layout, ctx.d2d_brush);
	ctx.d2d_rt->EndDraw();
	layout->Release();
	layout = NULL;

	// read texture from d3d
	ctx.d3d_device->CopyResource(ctx.d3d_texture2, ctx.d3d_texture1);

	D3D10_MAPPED_TEXTURE2D mapped = {0};
	if(FAILED(hr = ctx.d3d_texture2->Map(0, D3D10_MAP_READ, 0, &mapped)))
	{
		nf_explain_hr(hr, "can't map d3d texture");
		return -1;
	}

	for(size_t j = aabb.y; j < aabb.y + aabb.h; ++j)
		// hardcoded BGRA8 format
		memcpy(
			(uint8_t*)bitmap + (j * w + aabb.x) * 4,
			(uint8_t*)mapped.pData + j * mapped.RowPitch + aabb.x,
			aabb.w * 4);

	ctx.d3d_texture2->Unmap(0);
	return 0;
}