void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) { if (!BeginTargetDraw()) return; Gdiplus::Color color; brush.GetColor(&color); Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush; HRESULT hr = m_Target->CreateSolidColorBrush(ToColorF(color), solidBrush.GetAddressOf()); if (SUCCEEDED(hr)) { TextFormatD2D& formatD2D = (TextFormatD2D&)format; const bool right = formatD2D.GetHorizontalAlignment() == Gfx::HorizontalAlignment::Right; formatD2D.CreateLayout(str, strLen, rect.Width, rect.Height); m_Target->DrawTextLayout( D2D1::Point2F(right ? rect.X - 2 : rect.X + 2.0f, rect.Y - 1.0f), formatD2D.m_TextLayout.Get(), solidBrush.Get()); } }
void CanvasD2D::DrawMaskedBitmap(Gdiplus::Bitmap* bitmap, Gdiplus::Bitmap* maskBitmap, const Gdiplus::Rect& dstRect, const Gdiplus::Rect& srcRect, const Gdiplus::Rect& srcRect2) { if (!BeginTargetDraw()) return; auto rDst = ToRectF(dstRect); auto rSrc = ToRectF(srcRect); Util::WICBitmapLockGDIP* bitmapLock = new Util::WICBitmapLockGDIP(); Gdiplus::Rect lockRect(srcRect2); Gdiplus::Status status = bitmap->LockBits( &lockRect, Gdiplus::ImageLockModeRead, PixelFormat32bppPARGB, bitmapLock->GetBitmapData()); if (status == Gdiplus::Ok) { D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); Microsoft::WRL::ComPtr<ID2D1Bitmap> d2dBitmap; HRESULT hr = m_Target->CreateSharedBitmap( __uuidof(IWICBitmapLock), bitmapLock, &props, d2dBitmap.GetAddressOf()); if (SUCCEEDED(hr)) { // Create bitmap brush from original |bitmap|. Microsoft::WRL::ComPtr<ID2D1BitmapBrush> brush; D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = D2D1::BitmapBrushProperties( D2D1_EXTEND_MODE_CLAMP, D2D1_EXTEND_MODE_CLAMP, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR); // "Move" and "scale" the |bitmap| to match the destination. D2D1_MATRIX_3X2_F translate = D2D1::Matrix3x2F::Translation(rDst.left, rDst.top); D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale( D2D1::SizeF((rDst.right - rDst.left) / (float)srcRect2.Width, (rDst.bottom - rDst.top) / (float)srcRect2.Height)); D2D1_BRUSH_PROPERTIES brushProps = D2D1::BrushProperties(1.0F, scale * translate); hr = m_Target->CreateBitmapBrush( d2dBitmap.Get(), propertiesXClampYClamp, brushProps, brush.GetAddressOf()); // Load the |maskBitmap| and use the bitmap brush to "fill" its contents. // Note: The image must be aliased when applying the opacity mask. if (SUCCEEDED(hr)) { Util::WICBitmapLockGDIP* maskBitmapLock = new Util::WICBitmapLockGDIP(); Gdiplus::Rect maskLockRect(0, 0, maskBitmap->GetWidth(), maskBitmap->GetHeight()); status = maskBitmap->LockBits( &maskLockRect, Gdiplus::ImageLockModeRead, PixelFormat32bppPARGB, maskBitmapLock->GetBitmapData()); if (status == Gdiplus::Ok) { D2D1_BITMAP_PROPERTIES maskProps = D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); Microsoft::WRL::ComPtr<ID2D1Bitmap> d2dMaskBitmap; hr = m_Target->CreateSharedBitmap( __uuidof(IWICBitmapLock), maskBitmapLock, &props, d2dMaskBitmap.GetAddressOf()); if (SUCCEEDED(hr)) { m_Target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); // required m_Target->FillOpacityMask( d2dMaskBitmap.Get(), brush.Get(), D2D1_OPACITY_MASK_CONTENT_GRAPHICS, &rDst, &rSrc); m_Target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); } maskBitmap->UnlockBits(bitmapLock->GetBitmapData()); } maskBitmapLock->Release(); } } bitmap->UnlockBits(bitmapLock->GetBitmapData()); } bitmapLock->Release(); }
void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush, bool applyInlineFormatting) { if (!BeginTargetDraw()) return; Gdiplus::Color color; brush.GetColor(&color); Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush; HRESULT hr = m_Target->CreateSolidColorBrush(ToColorF(color), solidBrush.GetAddressOf()); if (FAILED(hr)) return; TextFormatD2D& formatD2D = (TextFormatD2D&)format; if (!formatD2D.CreateLayout( m_Target.Get(), str, strLen, rect.Width, rect.Height, !m_AccurateText && m_TextAntiAliasing)) return; D2D1_POINT_2F drawPosition; drawPosition.x = [&]() { if (!m_AccurateText) { const float xOffset = formatD2D.m_TextFormat->GetFontSize() / 6.0f; switch (formatD2D.GetHorizontalAlignment()) { case HorizontalAlignment::Left: return rect.X + xOffset; case HorizontalAlignment::Right: return rect.X - xOffset; } } return rect.X; } (); drawPosition.y = [&]() { // GDI+ compatibility. float yPos = rect.Y - formatD2D.m_LineGap; switch (formatD2D.GetVerticalAlignment()) { case VerticalAlignment::Bottom: yPos -= formatD2D.m_ExtraHeight; break; case VerticalAlignment::Center: yPos -= formatD2D.m_ExtraHeight / 2; break; } return yPos; } (); if (formatD2D.m_Trimming) { D2D1_RECT_F clipRect = ToRectF(rect); if (m_CanUseAxisAlignClip) { m_Target->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_ALIASED); } else { const D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters(clipRect, nullptr, D2D1_ANTIALIAS_MODE_ALIASED); m_Target->PushLayer(layerParams, nullptr); } } // When different "effects" are used with inline coloring options, we need to // remove the previous inline coloring, then reapply them (if needed) - instead // of destroying/recreating the text layout. formatD2D.ResetInlineColoring(solidBrush.Get(), strLen); if (applyInlineFormatting) { formatD2D.ApplyInlineColoring(m_Target.Get(), &drawPosition); } m_Target->DrawTextLayout(drawPosition, formatD2D.m_TextLayout.Get(), solidBrush.Get()); if (applyInlineFormatting) { // Inline gradients require the drawing position, so in case that position // changes, we need a way to reset it after drawing time so on the next // iteration it will know the correct position. formatD2D.ResetGradientPosition(&drawPosition); } if (formatD2D.m_Trimming) { if (m_CanUseAxisAlignClip) { m_Target->PopAxisAlignedClip(); } else { m_Target->PopLayer(); } } }
void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& format, Gdiplus::RectF& rect, const Gdiplus::SolidBrush& brush) { if (!BeginTargetDraw()) return; Gdiplus::Color color; brush.GetColor(&color); Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush; HRESULT hr = m_Target->CreateSolidColorBrush(ToColorF(color), solidBrush.GetAddressOf()); if (FAILED(hr)) return; TextFormatD2D& formatD2D = (TextFormatD2D&)format; if (!formatD2D.CreateLayout( str, strLen, rect.Width, rect.Height, !m_AccurateText && m_TextAntiAliasing)) return; D2D1_POINT_2F drawPosition; drawPosition.x = [&]() { if (!m_AccurateText) { const float xOffset = formatD2D.m_TextFormat->GetFontSize() / 6.0f; switch (formatD2D.GetHorizontalAlignment()) { case HorizontalAlignment::Left: return rect.X + xOffset; case HorizontalAlignment::Right: return rect.X - xOffset; } } return rect.X; } (); drawPosition.y = [&]() { // GDI+ compatibility. float yPos = rect.Y - formatD2D.m_LineGap; switch (formatD2D.GetVerticalAlignment()) { case VerticalAlignment::Bottom: yPos -= formatD2D.m_ExtraHeight; break; case VerticalAlignment::Center: yPos -= formatD2D.m_ExtraHeight / 2; break; } return yPos; } (); if (formatD2D.m_Trimming) { D2D1_RECT_F clipRect = ToRectF(rect); if (m_CanUseAxisAlignClip) { m_Target->PushAxisAlignedClip(clipRect, D2D1_ANTIALIAS_MODE_ALIASED); } else { const D2D1_LAYER_PARAMETERS layerParams = D2D1::LayerParameters(clipRect, nullptr, D2D1_ANTIALIAS_MODE_ALIASED); m_Target->PushLayer(layerParams, nullptr); } } m_Target->DrawTextLayout(drawPosition, formatD2D.m_TextLayout.Get(), solidBrush.Get()); if (formatD2D.m_Trimming) { if (m_CanUseAxisAlignClip) { m_Target->PopAxisAlignedClip(); } else { m_Target->PopLayer(); } } }