// Begins drawing, allowing updates to content in the specified area.
void Scenario1ImageSource::BeginDraw(Windows::Foundation::Rect updateRect)
{
    POINT offset;
    ComPtr<IDXGISurface> surface;

    // Express target area as a native RECT type.
    RECT updateRectNative; 
    updateRectNative.left = static_cast<LONG>(updateRect.Left);
    updateRectNative.top = static_cast<LONG>(updateRect.Top);
    updateRectNative.right = static_cast<LONG>(updateRect.Right);
    updateRectNative.bottom = static_cast<LONG>(updateRect.Bottom);

    // Query for ISurfaceImageSourceNative interface.
    Microsoft::WRL::ComPtr<ISurfaceImageSourceNative> sisNative;    
    DX::ThrowIfFailed(
        reinterpret_cast<IUnknown*>(this)->QueryInterface(IID_PPV_ARGS(&sisNative))
        );

    // Begin drawing - returns a target surface and an offset to use as the top left origin when drawing.
    HRESULT beginDrawHR = sisNative->BeginDraw(updateRectNative, &surface, &offset);
 
    if (SUCCEEDED(beginDrawHR))
    {
        // Create render target.
        ComPtr<ID2D1Bitmap1> bitmap;
        DX::ThrowIfFailed(
            m_d2dContext->CreateBitmapFromDxgiSurface(
                surface.Get(),
                nullptr,
                &bitmap
                )
            );
        
        // Set context's render target.
        m_d2dContext->SetTarget(bitmap.Get());

        // Begin drawing using D2D context.
        m_d2dContext->BeginDraw();

        // Apply a clip and transform to constrain updates to the target update area.
        // This is required to ensure coordinates within the target surface remain
        // consistent by taking into account the offset returned by BeginDraw, and
        // can also improve performance by optimizing the area that is drawn by D2D.
        // Apps should always account for the offset output parameter returned by 
        // BeginDraw, since it may not match the passed updateRect input parameter's location.
        m_d2dContext->PushAxisAlignedClip(
            D2D1::RectF(
                static_cast<float>(offset.x),  
                static_cast<float>(offset.y),  
                static_cast<float>(offset.x + updateRect.Width),
                static_cast<float>(offset.y + updateRect.Height)  
                ),  
            D2D1_ANTIALIAS_MODE_ALIASED  
            );

        m_d2dContext->SetTransform(
            D2D1::Matrix3x2F::Translation(
                static_cast<float>(offset.x),
                static_cast<float>(offset.y)
                )
            );
    }
    else if (beginDrawHR == DXGI_ERROR_DEVICE_REMOVED || beginDrawHR == DXGI_ERROR_DEVICE_RESET)
    {
        // If the device has been removed or reset, attempt to recreate it and continue drawing.
        CreateDeviceResources();
        BeginDraw(updateRect);
    }
    else
    {
        // Notify the caller by throwing an exception if any other error was encountered.
        DX::ThrowIfFailed(beginDrawHR);
    }
}
void TextInlineFormat_Shadow::ApplyInlineFormat(ID2D1RenderTarget* target, IDWriteTextLayout* layout,
	ID2D1SolidColorBrush* solidBrush, const UINT32& strLen, const D2D1_POINT_2F& drawPosition)
{
	if (!target || !layout) return;

	// In order to make a shadow effect using the built-in D2D effect, we first need to make
	// certain parts of the string transparent. We then draw only the parts of the string we
	// we want a shadow for onto a memory bitmap. From this bitmap we can create the shadow
	// effect and draw it.

	D2D1_COLOR_F color = D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f);
	Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> transparent;
	HRESULT hr = target->CreateSolidColorBrush(color, transparent.GetAddressOf());
	if (FAILED(hr)) return;

	// Only change characters outside of the range(s) transparent
	for (UINT32 i = 0; i < strLen; ++i)
	{
		bool found = false;
		for (const auto& range : GetRanges())
		{
			if (range.length <= 0) continue;

			if (i >= range.startPosition && i < (range.startPosition + range.length))
			{
				found = true;
				break;
			}
		}

		if (!found)
		{
			DWRITE_TEXT_RANGE temp = { i, 1 };
			layout->SetDrawingEffect(transparent.Get(), temp);
		}
	}

	Microsoft::WRL::ComPtr<ID2D1Bitmap> bitmap;
	Microsoft::WRL::ComPtr<ID2D1BitmapRenderTarget> bTarget;
	hr = target->CreateCompatibleRenderTarget(bTarget.GetAddressOf());
	if (FAILED(hr)) return;
	
	// Draw onto memory bitmap target
	bTarget->BeginDraw();
	bTarget->DrawTextLayout(drawPosition, layout, solidBrush);
	bTarget->EndDraw();
	hr = bTarget->GetBitmap(bitmap.GetAddressOf());
	if (FAILED(hr)) return;

	// Shadow effects can only be drawn with a D2D device context
	Microsoft::WRL::ComPtr<ID2D1DeviceContext> dc;
	hr = target->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(dc.GetAddressOf()));
	if (FAILED(hr)) return;

	// Create shadow effect
	Microsoft::WRL::ComPtr<ID2D1Effect> shadow;
	hr = dc->CreateEffect(CLSID_D2D1Shadow, &shadow);
	if (FAILED(hr)) return;

	// Load shadow options to effect
	shadow->SetInput(0, bitmap.Get());
	shadow->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, m_Blur);
	shadow->SetValue(D2D1_SHADOW_PROP_COLOR, ToVector4F(m_Color));
	shadow->SetValue(D2D1_SHADOW_PROP_OPTIMIZATION, D2D1_SHADOW_OPTIMIZATION_SPEED);

	// Draw effect
	dc->DrawImage(shadow.Get(), m_Offset);
}