Example #1
0
bool CanvasD2D::MeasureTextLinesW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, UINT& lines)
{
	((TextFormatD2D&)format).m_TextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);

	IDWriteTextLayout* textLayout;
	HRESULT hr = c_DWFactory->CreateTextLayout(
		str,
		strLen,
		((TextFormatD2D&)format).m_TextFormat,
		rect.Width,
		10000,
		&textLayout);
	if (SUCCEEDED(hr))
	{
		DWRITE_TEXT_METRICS metrics;
		textLayout->GetMetrics(&metrics);
		rect.Width = metrics.width + 5.0f;
		rect.Height = metrics.height + 1.0f;  // 1.0f to get same result as GDI+.
		lines = metrics.lineCount;

		textLayout->Release();
		return true;
	}

	return false;
}
// Measure text
FW1_RECTF STDMETHODCALLTYPE CFW1FontWrapper::MeasureString(
	const WCHAR *pszString,
	const WCHAR *pszFontFamily,
	FLOAT FontSize,
	const FW1_RECTF *pLayoutRect,
	UINT Flags
) {
	FW1_RECTF stringRect = {pLayoutRect->Left, pLayoutRect->Top, pLayoutRect->Left, pLayoutRect->Top};
	
	IDWriteTextLayout *pTextLayout = createTextLayout(pszString, pszFontFamily, FontSize, pLayoutRect, Flags);
	if(pTextLayout != NULL) {
		// Get measurements
		/*DWRITE_OVERHANG_METRICS overhangMetrics;
		HRESULT hResult = pTextLayout->GetOverhangMetrics(&overhangMetrics);
		if(SUCCEEDED(hResult)) {
			stringRect.Left = floor(pLayoutRect->Left - overhangMetrics.left);
			stringRect.Top = floor(pLayoutRect->Top - overhangMetrics.top);
			stringRect.Right = ceil(pLayoutRect->Left + overhangMetrics.right);
			stringRect.Bottom = ceil(pLayoutRect->Top + overhangMetrics.bottom);
		}*/
		DWRITE_TEXT_METRICS textMetrics;
		HRESULT hResult = pTextLayout->GetMetrics(&textMetrics);
		if(SUCCEEDED(hResult)) {
			stringRect.Left = textMetrics.left;
			stringRect.Top = textMetrics.top;
			stringRect.Right = textMetrics.left + textMetrics.widthIncludingTrailingWhitespace;
			stringRect.Bottom = textMetrics.top + textMetrics.height;
		}

		pTextLayout->Release();
	}
	
	return stringRect;
}
Example #3
0
bool CDirectWriteRenderer::GetTextMetrics(
	LPCWSTR pText, int Length, CDirectWriteFont &Font, TextMetrics *pMetrics)
{
	if (pText == nullptr || pMetrics == nullptr)
		return false;
	if (m_pRenderTarget == nullptr)
		return false;

	HRESULT hr = E_UNEXPECTED;
	IDWriteFactory *pFactory = m_System.GetDWriteFactory();

	if (pFactory != nullptr) {
		IDWriteTextFormat *pTextFormat = Font.GetTextFormat();

		if (pTextFormat != nullptr) {
			D2D1_SIZE_F Size;
			IDWriteTextLayout *pTextLayout;

			pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
			pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
			if (Length < 0)
				Length = ::lstrlenW(pText);
			Size = m_pRenderTarget->GetSize();
			hr = pFactory->CreateTextLayout(
				pText,
				Length,
				pTextFormat,
				Size.width,
				Size.height,
				&pTextLayout);
			if (SUCCEEDED(hr)) {
				DWRITE_TEXT_METRICS Metrics;

				hr = pTextLayout->GetMetrics(&Metrics);
				if (SUCCEEDED(hr)) {
					pMetrics->Width = Metrics.width;
					pMetrics->WidthIncludingTrailingWhitespace = Metrics.widthIncludingTrailingWhitespace;
					pMetrics->Height = Metrics.height;
				}

				pTextLayout->Release();
			}

			pTextFormat->Release();
		}

		pFactory->Release();
	}

	return SUCCEEDED(hr);
}
Example #4
0
bool CanvasD2D::MeasureTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect)
{
	IDWriteTextLayout* textLayout;
	HRESULT hr = c_DWFactory->CreateTextLayout(
		str,
		strLen,
		((TextFormatD2D&)format).m_TextFormat,
		10000,
		10000,
		&textLayout);
	if (SUCCEEDED(hr))
	{
		DWRITE_TEXT_METRICS metrics;
		textLayout->GetMetrics(&metrics);
		rect.Width = metrics.width + 5.0f;
		rect.Height = metrics.height + 1.0f;  // 1.0f to get same result as GDI+.

		textLayout->Release();
		return true;
	}

	return false;
}
HRESULT Layout::Draw(float pageWidthInDips, ID2D1RenderTarget* renderTarget, ID2D1Brush* textBrush)
{
    HRESULT hr = S_OK;

    static UINT const fontResourceIDs[] = {  IDR_FONT_PERICLES, IDR_FONT_KOOTENAY };

    // Create a custom font collection comprising our two font resources. We could have done this
    // in the constructor rather than every time. However, if you set break points on the loader 
    // callbacks you'll find they're only called the first time the font collection is created. 
    // Thereafter the font collection data is cached so recreating it is quite fast.
    hr = fontContext_.Initialize();
    if (FAILED(hr))
        return hr;

    IDWriteFontCollection* fontCollection = NULL;
    hr = fontContext_.CreateFontCollection(
            fontResourceIDs,
            sizeof(fontResourceIDs),
            &fontCollection
            );
    if (FAILED(hr))
        return hr;

    // Set up for first paragraph.
    float const columnWidth = std::max<float>(minColumnWidth_, pageWidthInDips - leftMargin_ - rightMargin_);
    float y = 0;

    float spaceBefore = 0;
    IDWriteTextFormat* textFormat = NULL;

    size_t const formatCount = sizeof(formats_) / sizeof(formats_[0]);
    size_t const paragraphCount = sizeof(paragraphs_) / sizeof(paragraphs_[0]);

    // Iterate over all the paragraphs.
    for (size_t i = 0; i < paragraphCount; ++i)
    {
        // We create a different text format object for the first formatCount
        // paragraphs. After that we reuse the last text format object.
        if (i < formatCount)
        {
            // Create the text format object, specifying both the family name and the
            // custom font collection in which to look for the family name. DirectWrite
            // will only look for the family name in the specified collection so there
            // is no ambiguity even if the system font collection happens to have a font
            // with the same family name.
            SafeRelease(&textFormat);
            hr = g_dwriteFactory->CreateTextFormat(
                    formats_[i].familyName,
                    fontCollection,
                    DWRITE_FONT_WEIGHT_NORMAL,
                    DWRITE_FONT_STYLE_NORMAL,
                    DWRITE_FONT_STRETCH_NORMAL,
                    formats_[i].pointSize * (96.0f / 72),
                    L"en-us",
                    &textFormat
                    );

            spaceBefore = formats_[i].spaceBefore * (96.0f / 72);
        }

        IDWriteTextLayout* textLayout = NULL;
        if (SUCCEEDED(hr))
        {
            // Load the string.
            int const maxLength = 512;
            wchar_t charBuffer[maxLength];
            int stringLength = LoadString(g_instance, paragraphs_[i], charBuffer, maxLength);

            // Create the text layout object.
            hr = g_dwriteFactory->CreateTextLayout(
                    charBuffer,
                    stringLength,
                    textFormat,
                    columnWidth,
                    0,
                    &textLayout
                    );
        }

        if (SUCCEEDED(hr))
        {
            // Draw the text and update the y coordinate.
            y += spaceBefore;

            renderTarget->DrawTextLayout(
                D2D1::Point2F(leftMargin_, y),
                textLayout,
                textBrush
                );

            DWRITE_TEXT_METRICS metrics;
            hr = textLayout->GetMetrics(&metrics);
            y += metrics.height;
        }
        SafeRelease(&textLayout);

        if (FAILED(hr))
            break;
    }

    SafeRelease(&textFormat);
    SafeRelease(&fontCollection);

    return hr;
}
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;
}