diff --git a/.gitignore b/.gitignore index fd193a46b25..fc0cf0a396f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ build/ bld/ [Bb]in/ [Oo]bj/ +Generated Files/ # Visual Studio 2015 cache/options directory .vs/ diff --git a/Directory.Build.props b/Directory.Build.props index 4f6d23454b8..ca81a986166 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -65,7 +65,7 @@ - + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index fc33f4fc0c7..1f77bdbfbd9 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -282,6 +282,7 @@ + @@ -524,6 +525,7 @@ + Designer @@ -580,6 +582,9 @@ + + DirectWriteTextBlockPage.xaml + TabViewPage.xaml @@ -956,6 +961,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -1437,6 +1446,10 @@ {d4d78cba-b238-4794-89a0-4f1a2d8fea97} Microsoft.Toolkit.Uwp.UI.Controls.Graph + + {d4c7ac54-826a-4412-8461-a7c7fd86534b} + Microsoft.Toolkit.Uwp.UI.Controls.WinRT + {e9faabfb-d726-42c1-83c1-cb46a29fea81} Microsoft.Toolkit.Uwp.UI.Controls diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlock.png b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlock.png new file mode 100644 index 00000000000..55f02676d95 Binary files /dev/null and b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlock.png differ diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockCode.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockCode.bind new file mode 100644 index 00000000000..4a3f86e333f --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockCode.bind @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockPage.xaml new file mode 100644 index 00000000000..20d2538e161 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockPage.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockPage.xaml.cs new file mode 100644 index 00000000000..cffb3222941 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/DirectWriteTextBlock/DirectWriteTextBlockPage.xaml.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class DirectWriteTextBlockPage : Page + { + public DirectWriteTextBlockPage() + { + this.InitializeComponent(); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json index 1dcbea4074b..1be66093060 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json @@ -438,6 +438,17 @@ "XamlCodeFile": "FocusTrackerXaml.bind", "Icon": "/SamplePages/FocusTracker/FocusTracker.png", "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/developer-tools/FocusTracker.md" + }, + { + "Name": "DirectWriteTextBlock", + "Type": "DirectWriteTextBlockPage", + "About": "DirectWriteTextBlock is a text block like class which generates an image using the DirectWrite API and displays it. Display vertically oriented text with it.", + "CodeUrl": "https://github.com/Microsoft/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock", + "XamlCodeFile": "DirectWriteTextBlockCode.bind", + "Icon": "/SamplePages/DirectWriteTextBlock/DirectWriteTextBlock.png", + "ApiCheck": "Windows.UI.Xaml.Controls.ColorPicker", + "BadgeUpdateVersionRequired": "April 2018 Update required", + "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/DirectWriteTextBlock.md" } ] }, diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontCollectionLoader.cpp b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontCollectionLoader.cpp new file mode 100644 index 00000000000..671b29377a1 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontCollectionLoader.cpp @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pch.h" +#include +#include +#include +#include "DirectWriteFontFileEnumerator.h" +#include "DirectWriteFontCollectionLoader.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +winrt::com_ptr DirectWriteFontCollectionLoader::s_comInstance; + +DirectWriteFontCollectionLoader::DirectWriteFontCollectionLoader() +{ +} + +DirectWriteFontCollectionLoader::~DirectWriteFontCollectionLoader() +{ +} + +bool DirectWriteFontCollectionLoader::HasCustomFontFamily(Platform::String^ xamlFontFamily) +{ + // is there a .ttf in the path? + std::wstring wstringPath{ xamlFontFamily->Data() }; + std::transform(wstringPath.begin(), wstringPath.end(), wstringPath.begin(), towlower); + auto foundCustomFontFile = wstringPath.find(L".ttf#", 0); + return foundCustomFontFile != std::wstring::npos; +} + +void DirectWriteFontCollectionLoader::ParseXamlFontFamily(_In_ Platform::String^ xamlFontFamily, _Out_ DirectWriteUniversalPackageFontData& parsedFont) +{ + parsedFont = {}; + std::wstring wstringPath{ xamlFontFamily->Data() }; + auto delimLocation = wstringPath.find(L'#'); + if (delimLocation != std::wstring::npos) + { + auto path = wstringPath.substr(0, delimLocation); + std::replace(path.begin(), path.end(), L'/', L'\\'); + parsedFont.packageFontFilePath = path; + parsedFont.customFontName = wstringPath.substr(delimLocation + 1); + } +} + +bool DirectWriteFontCollectionLoader::FindCachedEnumerator(Platform::String^ xamlFontFamily, winrt::com_ptr& enumerator) +{ + for (auto& entry : m_fontEnumerators) + { + if (entry.customFont->Equals(xamlFontFamily)) + { + enumerator = entry.enumerator; + return true; + } + } + + return false; +} + +IFACEMETHODIMP DirectWriteFontCollectionLoader::CreateEnumeratorFromKey(_In_ IDWriteFactory* factory, void const* collectionKey, unsigned int collectionKeySize, _Outptr_ IDWriteFontFileEnumerator** fontFileEnumerator) +try +{ + *fontFileEnumerator = nullptr; + auto xamlFontFamily = ref new Platform::String(reinterpret_cast(collectionKey), collectionKeySize); + + if (HasCustomFontFamily(xamlFontFamily)) + { + winrt::com_ptr cachedEnumerator; + if (!FindCachedEnumerator(xamlFontFamily, cachedEnumerator)) + { + auto enumerator{ winrt::make_self() }; + DirectWriteUniversalPackageFontData parseData = {}; + ParseXamlFontFamily(xamlFontFamily, parseData); + winrt::check_hresult(enumerator->Initialize(factory, parseData)); + + FontEnumeratorEntry entry = {}; + entry.customFont = xamlFontFamily; + entry.enumerator = enumerator; + m_fontEnumerators.push_back(std::move(entry)); + cachedEnumerator = enumerator; + } + + winrt::check_hresult(cachedEnumerator->QueryInterface(IID_PPV_ARGS(fontFileEnumerator))); + } + else + { + winrt::throw_hresult(E_INVALIDARG); + } + + return S_OK; +} +catch (...) +{ + return winrt::to_hresult(); +} + +winrt::com_ptr& DirectWriteFontCollectionLoader::GetInstance() +{ + if (!s_comInstance) + { + s_comInstance = winrt::make(); + } + + return s_comInstance; +} + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontCollectionLoader.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontCollectionLoader.h new file mode 100644 index 00000000000..1bc03199654 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontCollectionLoader.h @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once +#include "DirectWriteUniversalPackageFontData.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +/// +/// This is just to glue together a custom font file in the Universal Windows app package +/// to a custom DWrite Font. All it does is provide an enumerator that returns 1 font (the custom font) +/// and doesn't support things like font fallbacks. +/// +struct DirectWriteFontCollectionLoader : winrt::implements +{ +public: + DirectWriteFontCollectionLoader(); + virtual ~DirectWriteFontCollectionLoader(); + + /// + /// Create the enumerator to the Universal Windows Application package. + /// + IFACEMETHOD(CreateEnumeratorFromKey)( + _In_ IDWriteFactory* factory, + void const* collectionKey, // XAML FontFamily Syntax (something.ttf)#font + unsigned int collectionKeySize, + _Outptr_ IDWriteFontFileEnumerator** fontFileEnumerator + ); + + /// + /// This sees if the incoming XAML FontFamily value has something that looks like + /// a custom font file like foo.ttf#bar + /// + static bool HasCustomFontFamily(Platform::String^ xamlFontFamily); + + /// + /// This parses something that looks like /foo/bar.ttf#baz into the ttf path and the font name (baz). + /// + static void ParseXamlFontFamily(Platform::String^ xamlFontFamily, _Out_ DirectWriteUniversalPackageFontData& parsedFont); + + /// + /// Get the singleton loader. + /// + static winrt::com_ptr& GetInstance(); + +private: + struct FontEnumeratorEntry + { + Platform::String^ customFont; + winrt::com_ptr enumerator; + }; + + // enumerators are cached due to memory usages. + bool FindCachedEnumerator(Platform::String^ xamlFontFamily, winrt::com_ptr& enumerator); + + std::vector m_fontEnumerators; + static winrt::com_ptr s_comInstance; +}; + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontFileEnumerator.cpp b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontFileEnumerator.cpp new file mode 100644 index 00000000000..a48e8870b38 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontFileEnumerator.cpp @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pch.h" +#include "DirectWriteFontFileEnumerator.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +using namespace Windows::Storage; + +DirectWriteFontFileEnumerator::DirectWriteFontFileEnumerator() +{ +} + +DirectWriteFontFileEnumerator::~DirectWriteFontFileEnumerator() +{ +} + +HRESULT DirectWriteFontFileEnumerator::Initialize(_In_ IDWriteFactory* factory, const DirectWriteUniversalPackageFontData& packageFont) +try +{ + if ((factory == nullptr) || packageFont.packageFontFilePath.empty() || packageFont.customFontName.empty()) + { + winrt::throw_hresult(E_INVALIDARG); + } + + m_factory.attach(factory); + m_packageFontArgs = packageFont; + return S_OK; +} +catch (...) +{ + return winrt::to_hresult(); +} + +IFACEMETHODIMP DirectWriteFontFileEnumerator::MoveNext(_Out_ BOOL* hasCurrentFile) +try +{ + *hasCurrentFile = FALSE; + if (!m_enumerated) + { + m_currentFontFile = nullptr; + auto uwappStorage = Windows::ApplicationModel::Package::Current->InstalledLocation; + std::wstring filePath{ uwappStorage->Path->Data() }; + filePath.append(m_packageFontArgs.packageFontFilePath); + winrt::check_hresult(m_factory->CreateFontFileReference(filePath.c_str(), nullptr, m_currentFontFile.put())); + + *hasCurrentFile = TRUE; + m_enumerated = true; + } + + return S_OK; +} +catch (...) +{ + return winrt::to_hresult(); +} + +IFACEMETHODIMP DirectWriteFontFileEnumerator::GetCurrentFontFile(_Outptr_ IDWriteFontFile** fontFile) +try +{ + m_currentFontFile.copy_to(fontFile); + return S_OK; +} +catch (...) +{ + return winrt::to_hresult(); +} + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontFileEnumerator.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontFileEnumerator.h new file mode 100644 index 00000000000..548703af69f --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteFontFileEnumerator.h @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once +#include "DirectWriteUniversalPackageFontData.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +/// +/// This is an enumerator that basically just enumerates 1 custom font into DWrite from the Universal Windows App package. +/// It's extremely simplistic and basically just connects the Universal App Package files to DWrite. +/// +struct DirectWriteFontFileEnumerator : winrt::implements +{ +public: + DirectWriteFontFileEnumerator(); + virtual ~DirectWriteFontFileEnumerator(); + + /// + /// This is called consecutively by DWrite until we return FALSE to hasCurrentFile to enumerate the custom + /// font + /// + IFACEMETHOD(MoveNext)(_Out_ BOOL* hasCurrentFile); + + /// + /// This is called by DWrite to get the custom font file. + /// + IFACEMETHOD(GetCurrentFontFile)(_Outptr_ IDWriteFontFile** fontFile); + + /// + /// Initializes the enumerator + /// + HRESULT Initialize(_In_ IDWriteFactory* factory, const DirectWriteUniversalPackageFontData& packageFont); + +private: + winrt::com_ptr m_factory; + winrt::com_ptr m_currentFontFile; + DirectWriteUniversalPackageFontData m_packageFontArgs = {}; + bool m_enumerated = false; +}; + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteRenderArgBuilder.cpp b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteRenderArgBuilder.cpp new file mode 100644 index 00000000000..fabc73217b5 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteRenderArgBuilder.cpp @@ -0,0 +1,335 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pch.h" +#include "DirectWriteRenderArgBuilder.h" +#include "DirectWriteResourceManager.h" +#include "DirectWriteFontCollectionLoader.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +using namespace Platform; +using namespace Windows::UI; +using namespace Windows::UI::Text; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::Globalization; +using namespace Windows::Graphics::Display; +using namespace Windows::Foundation; + +DirectWriteRenderArgBuilder::DirectWriteRenderArgBuilder() +{ + // default values + m_builtArgs.availableHeight = 0; + m_builtArgs.availableWidth = 0; + m_builtArgs.flowDirection = DWRITE_FLOW_DIRECTION::DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT; + m_builtArgs.fontFamily = ref new String(L"Segoe UI"); + m_builtArgs.fontSize = 15; + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_NORMAL; + m_builtArgs.fontStyle = DWRITE_FONT_STYLE::DWRITE_FONT_STYLE_NORMAL; + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_NORMAL; + m_builtArgs.foregroundColor = Windows::UI::Colors::Black; + m_builtArgs.rawPixelsPerViewPixel = 1; + m_builtArgs.readingDirection = DWRITE_READING_DIRECTION::DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; + m_builtArgs.textLocale = ref new String(L"en-US"); + m_builtArgs.textWrapping = DWRITE_WORD_WRAPPING::DWRITE_WORD_WRAPPING_NO_WRAP; + m_builtArgs.fontCollection = nullptr; + m_builtArgs.textAlignment = DWRITE_TEXT_ALIGNMENT_LEADING; +} + +void DirectWriteRenderArgBuilder::SetFontFamily(FontFamily^ fontFamily) +{ + String^ resultFontFamily; + + // try to get the FontFamily property first. + auto controlFontFamily = fontFamily; + if ((controlFontFamily != nullptr) && !controlFontFamily->Source->IsEmpty()) + { + // if there's something in the font family, use it. + resultFontFamily = controlFontFamily->Source; + } + + // if nothing was in the font family, try the XAML default value. + if (resultFontFamily->IsEmpty() && (controlFontFamily != nullptr)) + { + auto xamlDefault = FontFamily::XamlAutoFontFamily; + if ((xamlDefault != nullptr) && !xamlDefault->Source->IsEmpty()) + { + resultFontFamily = xamlDefault->Source; + } + } + + // if the xaml default failed for some reason, hardcode to Segoe UI as last fallback. + if (resultFontFamily->IsEmpty()) + { + resultFontFamily = L"Segoe UI"; + } + + m_builtArgs.fontFamily = resultFontFamily; + BuildFontCollection(resultFontFamily); +} + +void DirectWriteRenderArgBuilder::SetText(Platform::String^ text) +{ + m_builtArgs.text = text; +} + +void DirectWriteRenderArgBuilder::SetTextLocale(Platform::String^ textLocale) +{ + if (Language::IsWellFormed(textLocale)) + { + m_builtArgs.textLocale = textLocale; + } + else + { + // default to en-US. + m_builtArgs.textLocale = ref new String(L"en-US"); + } +} + +void DirectWriteRenderArgBuilder::SetForegroundBrush(Brush^ brush) +{ + auto solidColorBrush = dynamic_cast(brush); + if (solidColorBrush != nullptr) + { + m_builtArgs.foregroundColor = solidColorBrush->Color; + } + else + { + m_builtArgs.foregroundColor = Colors::Black; + } +} + +void DirectWriteRenderArgBuilder::SetFontStyle(FontStyle fontStyle) +{ + switch (fontStyle) + { + case FontStyle::Normal: __fallthrough; + default: + m_builtArgs.fontStyle = DWRITE_FONT_STYLE::DWRITE_FONT_STYLE_NORMAL; + break; + case FontStyle::Italic: + m_builtArgs.fontStyle = DWRITE_FONT_STYLE::DWRITE_FONT_STYLE_ITALIC; + break; + case FontStyle::Oblique: + m_builtArgs.fontStyle = DWRITE_FONT_STYLE::DWRITE_FONT_STYLE_OBLIQUE; + break; + } +} + +void DirectWriteRenderArgBuilder::SetFontStretch(FontStretch fontStretch) +{ + switch (fontStretch) + { + case FontStretch::Normal: __fallthrough; + default: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_NORMAL; + break; + case FontStretch::Condensed: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_CONDENSED; + break; + case FontStretch::Expanded: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_EXPANDED; + break; + case FontStretch::ExtraCondensed: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_EXTRA_CONDENSED; + break; + case FontStretch::ExtraExpanded: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_EXTRA_EXPANDED; + break; + case FontStretch::SemiCondensed: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_SEMI_CONDENSED; + break; + case FontStretch::SemiExpanded: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_SEMI_EXPANDED; + break; + case FontStretch::UltraCondensed: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_ULTRA_CONDENSED; + break; + case FontStretch::UltraExpanded: + m_builtArgs.fontStretch = DWRITE_FONT_STRETCH::DWRITE_FONT_STRETCH_ULTRA_EXPANDED; + break; + } +} + +void DirectWriteRenderArgBuilder::SetTextReadingDirection(DirectWriteReadingDirection textReadingDirection) +{ + switch (textReadingDirection) + { + case DirectWriteReadingDirection::TopToBottom: __fallthrough; + default: + m_builtArgs.readingDirection = DWRITE_READING_DIRECTION::DWRITE_READING_DIRECTION_TOP_TO_BOTTOM; + break; + case DirectWriteReadingDirection::LeftToRight: + m_builtArgs.readingDirection = DWRITE_READING_DIRECTION::DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; + break; + case DirectWriteReadingDirection::RightToLeft: + m_builtArgs.readingDirection = DWRITE_READING_DIRECTION::DWRITE_READING_DIRECTION_RIGHT_TO_LEFT; + break; + case DirectWriteReadingDirection::BottomToTop: + m_builtArgs.readingDirection = DWRITE_READING_DIRECTION::DWRITE_READING_DIRECTION_BOTTOM_TO_TOP; + break; + } +} + +void DirectWriteRenderArgBuilder::SetFlowDirection(FlowDirection flowDirection) +{ + switch (flowDirection) + { + case FlowDirection::LeftToRight: __fallthrough; + default: + m_builtArgs.flowDirection = DWRITE_FLOW_DIRECTION::DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT; + break; + case FlowDirection::RightToLeft: + m_builtArgs.flowDirection = DWRITE_FLOW_DIRECTION::DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT; + break; + } +} + +void DirectWriteRenderArgBuilder::SetFontWeight(FontWeight fontWeight) +{ + auto weight = fontWeight.Weight; + if (weight == FontWeights::Black.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_BLACK; + } + else if (weight == FontWeights::Bold.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_BOLD; + } + else if (weight == FontWeights::ExtraBlack.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_EXTRA_BLACK; + } + else if (weight == FontWeights::ExtraBold.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_EXTRA_BOLD; + } + else if (weight == FontWeights::ExtraLight.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_EXTRA_LIGHT; + } + else if (weight == FontWeights::Light.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_LIGHT; + } + else if (weight == FontWeights::SemiBold.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_SEMI_BOLD; + } + else if (weight == FontWeights::SemiLight.Weight) + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_SEMI_LIGHT; + } + else + { + m_builtArgs.fontWeight = DWRITE_FONT_WEIGHT::DWRITE_FONT_WEIGHT_NORMAL; + } +} + +void DirectWriteRenderArgBuilder::SetTextWrapping(DirectWriteWordWrapping textWrapping) +{ + switch (textWrapping) + { + case DirectWriteWordWrapping::NoWrap: + default: + m_builtArgs.textWrapping = DWRITE_WORD_WRAPPING::DWRITE_WORD_WRAPPING_NO_WRAP; + break; + case DirectWriteWordWrapping::Wrap: + m_builtArgs.textWrapping = DWRITE_WORD_WRAPPING::DWRITE_WORD_WRAPPING_WRAP; + break; + case DirectWriteWordWrapping::WholeWord: + m_builtArgs.textWrapping = DWRITE_WORD_WRAPPING::DWRITE_WORD_WRAPPING_WHOLE_WORD; + break; + case DirectWriteWordWrapping::EmergencyBreak: + m_builtArgs.textWrapping = DWRITE_WORD_WRAPPING::DWRITE_WORD_WRAPPING_EMERGENCY_BREAK; + break; + case DirectWriteWordWrapping::Character: + m_builtArgs.textWrapping = DWRITE_WORD_WRAPPING::DWRITE_WORD_WRAPPING_CHARACTER; + break; + } +} + +void DirectWriteRenderArgBuilder::SetTextAlignment(DirectWriteTextAlignment textAlignment) +{ + switch (textAlignment) + { + case DirectWriteTextAlignment::Leading: + default: + m_builtArgs.textAlignment = DWRITE_TEXT_ALIGNMENT::DWRITE_TEXT_ALIGNMENT_LEADING; + break; + case DirectWriteTextAlignment::Trailing: + m_builtArgs.textAlignment = DWRITE_TEXT_ALIGNMENT::DWRITE_TEXT_ALIGNMENT_TRAILING; + break; + case DirectWriteTextAlignment::Center: + m_builtArgs.textAlignment = DWRITE_TEXT_ALIGNMENT::DWRITE_TEXT_ALIGNMENT_CENTER; + break; + case DirectWriteTextAlignment::Justified: + m_builtArgs.textAlignment = DWRITE_TEXT_ALIGNMENT::DWRITE_TEXT_ALIGNMENT_JUSTIFIED; + break; + } +} + +void DirectWriteRenderArgBuilder::SetFontSize(double fontSize) +{ + m_builtArgs.fontSize = static_cast(fontSize); + if (m_builtArgs.fontSize <= 0) + { + m_builtArgs.fontSize = 15.0f; + } +} + +void DirectWriteRenderArgBuilder::SetDPI(double rawPixelsPerViewPixel) +{ + m_builtArgs.rawPixelsPerViewPixel = static_cast(rawPixelsPerViewPixel); + if (m_builtArgs.rawPixelsPerViewPixel <= 0) + { + m_builtArgs.rawPixelsPerViewPixel = 1.0f; + } +} + +void DirectWriteRenderArgBuilder::SetAvailableWidth(float availableWidth) +{ + m_builtArgs.availableWidth = availableWidth; +} + +void DirectWriteRenderArgBuilder::SetAvailableHeight(float availableHeight) +{ + m_builtArgs.availableHeight = availableHeight; +} + +DirectWriteTextRenderArgs& DirectWriteRenderArgBuilder::BuildRenderArgs() +{ + return m_builtArgs; +} + +void DirectWriteRenderArgBuilder::BuildFontCollection(Platform::String^ fontFamily) +{ + // default arg is system font collection, what we're looking for is if we're trying to + // find a local custom ttf file. + if (DirectWriteFontCollectionLoader::HasCustomFontFamily(fontFamily)) + { + auto resourceManager = DirectWriteResourceManager::GetInstance(); + auto dwriteFactory = resourceManager->GetDirectWriteFactoryNoRef(); + DirectWriteUniversalPackageFontData parseData = {}; + DirectWriteFontCollectionLoader::ParseXamlFontFamily(fontFamily, parseData); + auto customLoader = DirectWriteFontCollectionLoader::GetInstance(); + + // the key is a void* meaning the size is actual size. + auto fontFamilyString = fontFamily->Data(); + auto fontFamilySize = fontFamily->Length() * sizeof(wchar_t); + dwriteFactory->CreateCustomFontCollection(customLoader.get(), fontFamilyString, static_cast(fontFamilySize), m_builtArgs.fontCollection.put()); + + // set font family to the parsed font family. + m_builtArgs.fontFamily = ref new String(parseData.customFontName.data(), static_cast(parseData.customFontName.size())); + } + else + { + // else assume it's a system font for now. We could do a lookup, but that would actually slow things down. + m_builtArgs.fontCollection = nullptr; + } +} + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteRenderArgBuilder.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteRenderArgBuilder.h new file mode 100644 index 00000000000..d9c50eac95a --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteRenderArgBuilder.h @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +BEGIN_NAMESPACE_CONTROLS_WINRT + +public enum class DirectWriteReadingDirection : int +{ + LeftToRight, + RightToLeft, + TopToBottom, + BottomToTop +}; + +public enum class DirectWriteTextAlignment : int +{ + Leading, + Trailing, + Center, + Justified +}; + +public enum class DirectWriteWordWrapping : int +{ + Wrap, + NoWrap, + EmergencyBreak, + WholeWord, + Character +}; + +/// +/// These are arguments which are used to render the DWrite string. +/// +struct DirectWriteTextRenderArgs +{ + Platform::String^ fontFamily; + Platform::String^ text; + Platform::String^ textLocale; + Windows::UI::Color foregroundColor; + DWRITE_FONT_STYLE fontStyle; + DWRITE_FONT_STRETCH fontStretch; + DWRITE_READING_DIRECTION readingDirection; + DWRITE_FLOW_DIRECTION flowDirection; + DWRITE_FONT_WEIGHT fontWeight; + DWRITE_WORD_WRAPPING textWrapping; + DWRITE_TEXT_ALIGNMENT textAlignment; + float fontSize; + float rawPixelsPerViewPixel; + float availableWidth; + float availableHeight; + winrt::com_ptr fontCollection; +}; + +/// +/// This class translates input from the XAML world into a DirectWriteTextRenderArgs struct +/// meant to be used with the DWrite world. If the user passes invalid values in, it attempts +/// to correct by setting them back to a known default value. This is because in case the user +/// is using the text block from C# (most users are expected to do this), a crash ultimately +/// just gives them a "something went wrong and a native exception was thrown" which is not +/// super helpful. Recovery will at least render something that looks incorrect on the screen. +/// +class DirectWriteRenderArgBuilder +{ +public: + DirectWriteRenderArgBuilder(); + + /// + /// The font family, by default Segoe UI + /// + void SetFontFamily(Windows::UI::Xaml::Media::FontFamily^ fontFamily); + + /// + /// The text to render, empty string by default. + /// + void SetText(Platform::String^ text); + + /// + /// The text locale for DWrite, en-US by default. + /// + void SetTextLocale(Platform::String^ textLocale); + + /// + /// The foreground brush, Black by default + /// + void SetForegroundBrush(Windows::UI::Xaml::Media::Brush^ brush); + + /// + /// The font style, Normal by default + /// + void SetFontStyle(Windows::UI::Text::FontStyle fontStyle); + + /// + /// The font stretch, normal by default + /// + void SetFontStretch(Windows::UI::Text::FontStretch fontStretch); + + /// + /// The text reading direction, top to bottom by default + /// + void SetTextReadingDirection(DirectWriteReadingDirection textReadingDirection); + + /// + /// The flow direction, LeftToRight by default + /// + void SetFlowDirection(Windows::UI::Xaml::FlowDirection flowDirection); + + /// + /// The font weight, Normal by default + /// + void SetFontWeight(Windows::UI::Text::FontWeight fontWeight); + + /// + /// The font size, 15 by default. + /// + void SetFontSize(double fontSize); + + /// + /// The DPI to render at, 1 by default + /// + void SetDPI(double rawPixelsPerViewPixel); + + /// + /// The available width to render at + /// + void SetAvailableWidth(float availableWidth); + + /// + /// The available height to render at. + /// + void SetAvailableHeight(float availableHeight); + + /// + /// The text wrap mode, None by default. + /// + void SetTextWrapping(DirectWriteWordWrapping textWrapping); + + /// + /// The text alignment mode, Leading by default. + /// + void SetTextAlignment(DirectWriteTextAlignment textAlignment); + + + /// + /// The render arguments. + /// + DirectWriteTextRenderArgs& BuildRenderArgs(); + +private: + void BuildFontCollection(Platform::String^ fontFamily); + DirectWriteTextRenderArgs m_builtArgs = {}; +}; + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteResourceManager.cpp b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteResourceManager.cpp new file mode 100644 index 00000000000..ec64171b096 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteResourceManager.cpp @@ -0,0 +1,138 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pch.h" +#include "DirectWriteFontCollectionLoader.h" +#include "DirectWriteResourceManager.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +std::unique_ptr DirectWriteResourceManager::s_instance; + +DirectWriteResourceManager::DirectWriteResourceManager() +{ +} + +DirectWriteResourceManager::~DirectWriteResourceManager() +{ +} + +IDWriteFactory* DirectWriteResourceManager::GetDirectWriteFactoryNoRef() +{ + winrt::check_hresult(InitializeDeviceResources()); + return m_dwriteFactory.get(); +} + +ID3D11Device* DirectWriteResourceManager::GetD3dDeviceNoRef() +{ + winrt::check_hresult(InitializeDeviceResources()); + return m_d3dDevice.get(); +} + +ID2D1DeviceContext* DirectWriteResourceManager::GetD2dDCNoRef() +{ + winrt::check_hresult(InitializeDeviceResources()); + return m_d2dContext.get(); +} + +IDXGIDevice* DirectWriteResourceManager::GetDXGIDeviceNoRef() +{ + winrt::check_hresult(InitializeDeviceResources()); + return m_dxgiDevice.get(); +} + +HRESULT DirectWriteResourceManager::RebuildDeviceResources() +{ + m_deviceResourcesInitialized = false; + return InitializeDeviceResources(); +} + +HRESULT DirectWriteResourceManager::InitializeDeviceResources() +{ + if (!m_deviceResourcesInitialized) + { + UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + D3D_FEATURE_LEVEL supportedFeatureLevel; + + m_d3dDevice = nullptr; + m_d2dDevice = nullptr; + m_dwriteFactory = nullptr; + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + HRESULT hr = D3D11CreateDevice( + nullptr, // Specify nullptr to use the default adapter. + D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver. + 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. + creationFlags, // Set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + m_d3dDevice.put(), // Returns the Direct3D device created. + &supportedFeatureLevel, + nullptr + ); + + // log failures on the initial creation + if (FAILED(hr)) + { + // If the initialization fails, fall back to the WARP device. + winrt::check_hresult(D3D11CreateDevice( + nullptr, + D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device. + 0, + creationFlags, + featureLevels, + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, + m_d3dDevice.put(), + &supportedFeatureLevel, + nullptr + )); + } + + // Get the Direct3D 11.1 API device. + m_d3dDevice.as(m_dxgiDevice); + winrt::check_hresult(D2D1CreateDevice(m_dxgiDevice.get(), nullptr, m_d2dDevice.put())); + + winrt::check_hresult(m_d2dDevice->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + m_d2dContext.put() + )); + + winrt::check_hresult(DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(m_dwriteFactory.put()) + )); + + auto customLoader = DirectWriteFontCollectionLoader::GetInstance(); + m_dwriteFactory->RegisterFontCollectionLoader(customLoader.get()); + + m_deviceResourcesInitialized = true; + } + + return S_OK; +} + +DirectWriteResourceManager* DirectWriteResourceManager::GetInstance() +{ + if (s_instance == nullptr) + { + s_instance.reset(new DirectWriteResourceManager()); + } + + return s_instance.get(); +} + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteResourceManager.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteResourceManager.h new file mode 100644 index 00000000000..1e1cd02ccff --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteResourceManager.h @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +BEGIN_NAMESPACE_CONTROLS_WINRT + +/// +/// This manages D3D/DWrite resources and prevents reinitialization. +/// +class DirectWriteResourceManager +{ +public: + DirectWriteResourceManager(); + virtual ~DirectWriteResourceManager(); + + /// + /// This is a singleton to prevent reintializing D3D + /// + static DirectWriteResourceManager* GetInstance(); + + /// + /// The DWrite Factory, caller doesn't take a reference. + /// + IDWriteFactory* GetDirectWriteFactoryNoRef(); + + /// + /// The D3D Device, caller doesn't take a reference. + /// + ID3D11Device* GetD3dDeviceNoRef(); + + /// + /// The D2D Device, caller doesn't take a reference. + /// + ID2D1DeviceContext* GetD2dDCNoRef(); + + /// + /// The DXGI Device, caller doesn't take a reference. + /// + IDXGIDevice* GetDXGIDeviceNoRef(); + + /// + /// Initializes the device resources. + /// + HRESULT InitializeDeviceResources(); + + /// + /// Reinitializes the device resources. + /// + HRESULT RebuildDeviceResources(); + +private: + winrt::com_ptr m_dwriteFactory; + winrt::com_ptr m_d3dDevice; + winrt::com_ptr m_d2dDevice; + winrt::com_ptr m_d2dContext; + winrt::com_ptr m_dxgiDevice; + + static std::unique_ptr s_instance; + bool m_deviceResourcesInitialized = false; +}; + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteTextBlock.cpp b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteTextBlock.cpp new file mode 100644 index 00000000000..03da823d147 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteTextBlock.cpp @@ -0,0 +1,367 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pch.h" +#include "DirectWriteTextBlock.h" +#include + +BEGIN_NAMESPACE_CONTROLS_WINRT + +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Graphics::Display; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Documents; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Interop; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Media::Imaging; +using namespace Windows::UI::ViewManagement; + +DependencyProperty^ DirectWriteTextBlock::m_textProperty = DependencyProperty::Register( + L"Text", + Platform::String::typeid, + DirectWriteTextBlock::typeid, + ref new PropertyMetadata(L"", ref new PropertyChangedCallback(&DirectWriteTextBlock::OnDependencyPropertyChanged))); + +DependencyProperty^ DirectWriteTextBlock::m_textLocaleProperty = DependencyProperty::Register( + L"TextLocale", + Platform::String::typeid, + DirectWriteTextBlock::typeid, + ref new PropertyMetadata(L"en-US", ref new PropertyChangedCallback(&DirectWriteTextBlock::OnDependencyPropertyChanged))); + +DependencyProperty^ DirectWriteTextBlock::m_textReadingDirectionProperty = DependencyProperty::Register( + L"TextReadingDirection", + DirectWriteReadingDirection::typeid, + DirectWriteTextBlock::typeid, + ref new PropertyMetadata(ref new Platform::Box(DirectWriteReadingDirection::TopToBottom), ref new PropertyChangedCallback(&DirectWriteTextBlock::OnDependencyPropertyChanged))); + +DependencyProperty^ DirectWriteTextBlock::m_textWrapProperty = DependencyProperty::Register( + L"TextWrap", + DirectWriteWordWrapping::typeid, + DirectWriteTextBlock::typeid, + ref new PropertyMetadata(ref new Platform::Box(DirectWriteWordWrapping::NoWrap), ref new PropertyChangedCallback(&DirectWriteTextBlock::OnDependencyPropertyChanged))); + +DependencyProperty^ DirectWriteTextBlock::m_textAlignmentProperty = DependencyProperty::Register( + L"TextAlign", + DirectWriteTextAlignment::typeid, + DirectWriteTextBlock::typeid, + ref new PropertyMetadata(ref new Platform::Box(DirectWriteTextAlignment::Leading), ref new PropertyChangedCallback(&DirectWriteTextBlock::OnDependencyPropertyChanged))); + + +DirectWriteTextBlock::DirectWriteTextBlock() +{ + DefaultStyleKey = "Microsoft.Toolkit.Uwp.UI.Controls.WinRT.DirectWriteTextBlock"; + + m_displayInfo = DisplayInformation::GetForCurrentView(); + m_dpiChangedToken = m_displayInfo->DpiChanged += ref new TypedEventHandler(this, &DirectWriteTextBlock::OnDpiChanged); + + m_accessibilitySettings = ref new AccessibilitySettings(); + m_highContrastChangedToken = m_accessibilitySettings->HighContrastChanged += ref new TypedEventHandler(this, &DirectWriteTextBlock::OnHighContrastSettingsChanged); + m_isHighContrast = m_accessibilitySettings->HighContrast; + +#define REGISTER_INHERITED_PROPERTY_CALLBACK(token, inheritedProperty) \ + token = RegisterPropertyChangedCallback(inheritedProperty, ref new DependencyPropertyChangedCallback(&DirectWriteTextBlock::OnInheritedDependencyPropertyChanged)) + + REGISTER_INHERITED_PROPERTY_CALLBACK(m_flowDirectionChangedToken, FlowDirectionProperty); + REGISTER_INHERITED_PROPERTY_CALLBACK(m_foregroundChangedToken, ForegroundProperty); + REGISTER_INHERITED_PROPERTY_CALLBACK(m_fontSizeChangedToken, FontSizeProperty); + REGISTER_INHERITED_PROPERTY_CALLBACK(m_fontFamilyChangedToken, FontFamilyProperty); + REGISTER_INHERITED_PROPERTY_CALLBACK(m_fontStretchChangedToken, FontStretchProperty); + REGISTER_INHERITED_PROPERTY_CALLBACK(m_fontStyleChangedToken, FontStyleProperty); + REGISTER_INHERITED_PROPERTY_CALLBACK(m_fontWeightChangedToken, FontWeightProperty); +#undef REGISTER_INHERITED_PROPERTY_CALLBACK +} + +DirectWriteTextBlock::~DirectWriteTextBlock() +{ + Close(); +} + +void DirectWriteTextBlock::OnApplyTemplate() +{ + // make XAML apply the template first + __super::OnApplyTemplate(); + + auto maybeImage = dynamic_cast(GetTemplateChild(L"Image")); + if (!maybeImage) + { + winrt::throw_hresult(E_NOT_VALID_STATE); + } + + // this border is essentially just used to emulate the XAML text high contrast background. + // the consumer can use it to set background to the text block, but normally, it should just be + // left null. + auto maybeBorder = dynamic_cast(GetTemplateChild(L"TextBackground")); + if (!maybeBorder) + { + winrt::throw_hresult(E_NOT_VALID_STATE); + } + + m_image = maybeImage; + m_textBackground = maybeBorder; +} + +Size DirectWriteTextBlock::MeasureOverride(Size availableSize) +{ + UpdateTextBrushesForHighContrast(); + auto displayInfo = DisplayInformation::GetForCurrentView(); + DirectWriteRenderArgBuilder builder; + builder.SetAvailableHeight(availableSize.Height); + builder.SetAvailableWidth(availableSize.Width); + builder.SetDPI(displayInfo->RawPixelsPerViewPixel); + builder.SetFlowDirection(FlowDirection); + builder.SetFontFamily(FontFamily); + builder.SetFontSize(FontSize); + builder.SetFontStretch(FontStretch); + builder.SetFontStyle(FontStyle); + builder.SetFontWeight(FontWeight); + builder.SetForegroundBrush(m_textForegroundBrush); + builder.SetText(Text); + builder.SetTextLocale(TextLocale); + builder.SetTextReadingDirection(TextReadingDirection); + builder.SetTextWrapping(TextWrap); + builder.SetTextAlignment(TextAlign); + + auto args = builder.BuildRenderArgs(); + UpdateElementsForHighContrast(); + + auto resultSize = RenderText(args); + + // call __super::Measure after we've already set the source to the new image. + __super::MeasureOverride(availableSize); + return resultSize; +} + +void DirectWriteTextBlock::UpdateTextBrushesForHighContrast() +{ + if (m_isHighContrast) + { + // XAML High Contrast TextBlock behavior emulation: XAML on high contrast basically sets + // a background to the TextBlock in order to get text to always appear in High Contrast. + // To emulate this, we basically look up the applicable text brushes from the system + // resource dictionary and override any foreground/background the user may have set like + // standard textblock would. + + auto resources = Application::Current->Resources; + auto highContrastForeground = static_cast(resources->Lookup(L"SystemColorWindowTextColor")); + auto highContrastBackground = static_cast(resources->Lookup(L"SystemColorWindowColor")); + m_textForegroundBrush = ref new SolidColorBrush(highContrastForeground); + m_textBackgroundBrush = ref new SolidColorBrush(highContrastBackground); + } + else + { + m_textForegroundBrush = this->Foreground; + m_textBackgroundBrush = this->Background; + } +} + +void DirectWriteTextBlock::UpdateElementsForHighContrast() +{ + if (m_textBackground) + { + m_textBackground->Background = m_textBackgroundBrush; + } +} + +void DirectWriteTextBlock::Close() +{ + +#define UNREGISTER_INHERITED_PROPERTY_CALLBACK(token, inheritedProperty) \ + if (token != 0) \ + { \ + UnregisterPropertyChangedCallback(inheritedProperty, token); \ + token = 0; \ + } + + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_flowDirectionChangedToken, FlowDirectionProperty); + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_foregroundChangedToken, ForegroundProperty); + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_fontSizeChangedToken, FontSizeProperty); + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_fontFamilyChangedToken, FontFamilyProperty); + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_fontStretchChangedToken, FontStretchProperty); + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_fontStyleChangedToken, FontStyleProperty); + UNREGISTER_INHERITED_PROPERTY_CALLBACK(m_fontWeightChangedToken, FontWeightProperty); + + if (m_dpiChangedToken.Value != 0) + { + m_displayInfo->DpiChanged -= m_dpiChangedToken; + m_dpiChangedToken = {}; + } + + if (m_highContrastChangedToken.Value != 0) + { + m_accessibilitySettings->HighContrastChanged -= m_highContrastChangedToken; + m_highContrastChangedToken = {}; + } + +#undef UNREGISTER_INHERITED_PROPERTY_CALLBACK +} + +Size DirectWriteTextBlock::RenderText(DirectWriteTextRenderArgs const& args) +{ + if ((m_image == nullptr) || args.text->IsEmpty()) + { + return Size(0.0f, 0.0f); + } + + auto resourceManager = DirectWriteResourceManager::GetInstance(); + auto scale = args.rawPixelsPerViewPixel; + auto scaledFontSize = args.fontSize * scale; + auto dwriteFactory = resourceManager->GetDirectWriteFactoryNoRef(); + + winrt::com_ptr textFormat; + winrt::check_hresult(dwriteFactory->CreateTextFormat( + args.fontFamily->Data(), + args.fontCollection.get(), + args.fontWeight, + args.fontStyle, + args.fontStretch, + scaledFontSize, + args.textLocale->Data(), + textFormat.put())); + + textFormat->SetWordWrapping(args.textWrapping); + + // Trying to set readingDirection + FlowDirection to LEFT_TO_RIGHT will result in + // a failed HRESULT From DWRITE. Since the defaults work fine for horizontal, only + // set these values for text orientation = vertical. + auto textReadingDirection = this->TextReadingDirection; + if (textReadingDirection != DirectWriteReadingDirection::LeftToRight) + { + textFormat->SetReadingDirection(args.readingDirection); + textFormat->SetFlowDirection(args.flowDirection); + } + + textFormat->SetTextAlignment(args.textAlignment); + + winrt::com_ptr textLayout; + winrt::check_hresult(dwriteFactory->CreateTextLayout( + args.text->Data(), + args.text->Length(), + textFormat.get(), + args.availableWidth, + args.availableHeight, + textLayout.put())); + + DWRITE_TEXT_METRICS textMetrics = {}; + winrt::check_hresult(textLayout->GetMetrics(&textMetrics)); + + // the image has to be scaled since we're manually handling DPI changes. + auto sisWidth = static_cast(std::ceil(textMetrics.width * scale)); + auto sisHeight = static_cast(std::ceil(textMetrics.height * scale)); + auto imageSource = ref new SurfaceImageSource(sisWidth, sisHeight); + auto sisUnknown = reinterpret_cast(imageSource); + winrt::com_ptr sisNative; + sisUnknown->QueryInterface(__uuidof(ISurfaceImageSourceNative), sisNative.put_void()); + sisNative->SetDevice(resourceManager->GetDXGIDeviceNoRef()); + + winrt::com_ptr surface; + RECT updateRect = { 0, 0, static_cast(sisWidth), static_cast(sisHeight) }; + POINT offset = { 0, 0 }; + m_lastDrawError = sisNative->BeginDraw(updateRect, surface.put(), &offset); + if (SUCCEEDED(m_lastDrawError)) + { + auto d2dContext = resourceManager->GetD2dDCNoRef(); + + // set the translation to the section of the bitmap that we want to render. + auto translate = D2D1::Matrix3x2F::Translation(static_cast(offset.x), static_cast(offset.y)); + d2dContext->SetTransform(translate); + + // this basically ensures the text background is transparent. + D2D1_BITMAP_PROPERTIES1 bitmapProperties = + { + { DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED }, + 96.f * scale, + 96.f * scale, + D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW + }; + + winrt::com_ptr bitmap; + winrt::check_hresult(d2dContext->CreateBitmapFromDxgiSurface( + surface.get(), + &bitmapProperties, + bitmap.put())); + + d2dContext->SetTarget(bitmap.get()); + d2dContext->BeginDraw(); + d2dContext->Clear(); + + winrt::com_ptr brush; + auto color = args.foregroundColor; + D2D1_COLOR_F d2dColor = D2D1::ColorF( + static_cast(color.R) / 255.0f, + static_cast(color.G) / 255.0f, + static_cast(color.B) / 255.0f, + static_cast(color.A) / 255.0f); + winrt::check_hresult(d2dContext->CreateSolidColorBrush(d2dColor, brush.put())); + + d2dContext->DrawText( + args.text->Data(), + args.text->Length(), + textFormat.get(), + D2D1::RectF(0, 0, static_cast(sisWidth), static_cast(sisHeight)), + brush.get(), + D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT); + + HRESULT d2dEndDrawResult = d2dContext->EndDraw(); + sisNative->EndDraw(); + + if (d2dEndDrawResult == D2DERR_RECREATE_TARGET) + { + winrt::check_hresult(resourceManager->RebuildDeviceResources()); + } + + m_image->Source = imageSource; + m_drawRetries = 0; + + // XAML will rescale, so we divide by scale here. + return Size{ static_cast(sisWidth / scale), static_cast(sisHeight / scale) }; + } + else if (m_drawRetries == 0) + { + // D2D draw can fail for multiple reasons where rebuilding the D3D device might be necessary. + winrt::check_hresult(resourceManager->RebuildDeviceResources()); + m_drawRetries++; + return RenderText(args); + } + else + { + // if we fail to draw 2x a retry, just bail. + return Size(0.0f, 0.0f); + } +} + +void DirectWriteTextBlock::OnDependencyPropertyChanged(_In_ DependencyObject^ d, _In_ DependencyPropertyChangedEventArgs^ /* e */) +{ + auto textBlockInstance = dynamic_cast(d); + if (textBlockInstance) + { + textBlockInstance->InvalidateMeasure(); + } +} + +void DirectWriteTextBlock::OnInheritedDependencyPropertyChanged(_In_ DependencyObject^ d, _In_ DependencyProperty^ /* e */) +{ + auto textBlockInstance = dynamic_cast(d); + if (textBlockInstance) + { + textBlockInstance->InvalidateMeasure(); + } +} + +void DirectWriteTextBlock::OnDpiChanged(_In_ DisplayInformation^ /* displayInfo */, _In_ Object^ /* obj */) +{ + InvalidateMeasure(); +} + +void DirectWriteTextBlock::OnHighContrastSettingsChanged(_In_ AccessibilitySettings^ accessibilitySettings, _In_ Object^ /* obj */) +{ + m_isHighContrast = accessibilitySettings->HighContrast; + InvalidateMeasure(); +} + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteTextBlock.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteTextBlock.h new file mode 100644 index 00000000000..0476948e15b --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteTextBlock.h @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include "DirectWriteResourceManager.h" +#include "DirectWriteRenderArgBuilder.h" + +BEGIN_NAMESPACE_CONTROLS_WINRT + +#define DEFINE_XAML_DEPENDENCY_PROPERTY(type, name, membername) \ + public: \ + property type name \ + { \ + type get() \ + { \ + return (type)(GetValue(membername)); \ + } \ + void set(type value) \ + { \ + SetValue(membername, value); \ + } \ + } \ + static property Windows::UI::Xaml::DependencyProperty^ name ## Property \ + { \ + Windows::UI::Xaml::DependencyProperty^ get() \ + { \ + return membername; \ + } \ + } \ + private: \ + static Windows::UI::Xaml::DependencyProperty^ membername; \ + public: + +#define DEFINE_XAML_DEPENDENCY_PROPERTY_VALUE_TYPE(type, name, membername) \ + public: \ + property type name \ + { \ + type get() \ + { \ + auto boxedType = dynamic_cast^>(GetValue(membername)); \ + if (boxedType != nullptr) \ + { \ + return boxedType->Value; \ + } \ + else \ + { \ + return static_cast((int)(GetValue(membername))); \ + } \ + } \ + void set(type value) \ + { \ + SetValue(membername, ref new Platform::Box(value)); \ + } \ + } \ + static property Windows::UI::Xaml::DependencyProperty^ name ## Property \ + { \ + Windows::UI::Xaml::DependencyProperty^ get() \ + { \ + return membername; \ + } \ + } \ + private: \ + static Windows::UI::Xaml::DependencyProperty^ membername; \ + public: + +/// +/// This is a text block which uses DirectWrite to draw text onto a bitmap image, allowing the user to orient text vertically for +/// East Asian languages and to support text rendering modes which aren't supported by XAML yet, but are supported by DirectWrite. +/// +/// Parts of this are built using C++/WinRT and will require the 1803 Windows SDK to build and use at minumum. +/// +/// +/// The current XAML code gen for C++/WinRT is in preview and results in a compile error so the main project class is C++/CX to get around +/// that limitation. +/// +/// Throwing out of this class will cause significant debuggability issues in C# consumers as they just get a "native exception was thrown." +/// Therefore, this class will attempt to recover from poor input like setting font size = 0. If something happens like a DWrite +/// method fails, that will throw an exception. +/// +[Windows::Foundation::Metadata::WebHostHidden] +public ref class DirectWriteTextBlock sealed : public Windows::UI::Xaml::Controls::Control +{ +public: + DirectWriteTextBlock(); + virtual ~DirectWriteTextBlock(); + + /// + /// The text to render + /// + DEFINE_XAML_DEPENDENCY_PROPERTY(Platform::String^, Text, m_textProperty); + + /// + /// The locale of the text to show + /// + DEFINE_XAML_DEPENDENCY_PROPERTY(Platform::String^, TextLocale, m_textLocaleProperty); + + /// + /// The reading direction of the text. + /// + DEFINE_XAML_DEPENDENCY_PROPERTY_VALUE_TYPE(DirectWriteReadingDirection, TextReadingDirection, m_textReadingDirectionProperty); + + /// + /// How the text is wrapped. To Wrap text, just set the Height or Width of this control. + /// + DEFINE_XAML_DEPENDENCY_PROPERTY_VALUE_TYPE(DirectWriteWordWrapping, TextWrap, m_textWrapProperty); + + /// + /// The direct write based alignment of the text. This is agnostic of XAML and only supports DirectWrite values. + /// + DEFINE_XAML_DEPENDENCY_PROPERTY_VALUE_TYPE(DirectWriteTextAlignment, TextAlign, m_textAlignmentProperty); + +protected: + // These are the methods we're overriding from IFrameworkElementOverrides. + void OnApplyTemplate() override; + Windows::Foundation::Size MeasureOverride(Windows::Foundation::Size availableSize) override; + +private: + static void OnDependencyPropertyChanged(_In_ Windows::UI::Xaml::DependencyObject^ d, _In_ Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ e); + static void OnInheritedDependencyPropertyChanged(_In_ Windows::UI::Xaml::DependencyObject^ d, _In_ Windows::UI::Xaml::DependencyProperty^ e); + void OnDpiChanged(_In_ Windows::Graphics::Display::DisplayInformation^ displayInfo, _In_ Platform::Object^ obj); + void OnHighContrastSettingsChanged(_In_ Windows::UI::ViewManagement::AccessibilitySettings^ accessibilitySettings, _In_ Platform::Object^ obj); + Windows::Foundation::Size RenderText(DirectWriteTextRenderArgs const& args); + void Close(); + void UpdateTextBrushesForHighContrast(); + void UpdateElementsForHighContrast(); + + Windows::Foundation::EventRegistrationToken m_dpiChangedToken = {}; + Windows::Foundation::EventRegistrationToken m_highContrastChangedToken = {}; + + long long m_foregroundChangedToken = 0; + long long m_fontSizeChangedToken = 0; + long long m_fontFamilyChangedToken = 0; + long long m_flowDirectionChangedToken = 0; + long long m_fontStretchChangedToken = 0; + long long m_fontWeightChangedToken = 0; + long long m_fontStyleChangedToken = 0; + + Windows::UI::ViewManagement::AccessibilitySettings^ m_accessibilitySettings; + Windows::UI::Xaml::Controls::Image^ m_image; + Windows::UI::Xaml::Controls::Border^ m_textBackground; + Windows::UI::Xaml::Media::Brush^ m_textForegroundBrush; + Windows::UI::Xaml::Media::Brush^ m_textBackgroundBrush; + Windows::Graphics::Display::DisplayInformation^ m_displayInfo; + bool m_isHighContrast = false; + HRESULT m_lastDrawError = S_OK; + unsigned int m_drawRetries = 0; +}; + +END_NAMESPACE_CONTROLS_WINRT diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteUniversalPackageFontData.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteUniversalPackageFontData.h new file mode 100644 index 00000000000..ae48537259d --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/DirectWriteTextBlock/DirectWriteUniversalPackageFontData.h @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +BEGIN_NAMESPACE_CONTROLS_WINRT + +struct DirectWriteUniversalPackageFontData +{ + std::wstring packageFontFilePath; + std::wstring customFontName; +}; + +END_NAMESPACE_CONTROLS_WINRT \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.targets b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.targets new file mode 100644 index 00000000000..0144421e37e --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.targets @@ -0,0 +1,20 @@ + + + + x86 + $(Platform) + + + + Microsoft.Toolkit.Uwp.UI.Controls.WinRT.dll + + + + + + + + $(MSBuildThisFileDirectory)..\..\Include;%(AdditionalIncludeDirectories) + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj new file mode 100644 index 00000000000..82b0f762ee6 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj @@ -0,0 +1,272 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {d4c7ac54-826a-4412-8461-a7c7fd86534b} + WindowsRuntimeComponent + Microsoft.Toolkit.Uwp.UI.Controls.WinRT + en-US + 14.0 + true + Windows Store + 10.0.17763.0 + 10.0.17763.0 + 10.0 + + + + DynamicLibrary + true + v141 + + + DynamicLibrary + true + v141 + + + DynamicLibrary + true + v141 + + + DynamicLibrary + false + true + v141 + + + DynamicLibrary + false + true + v141 + + + DynamicLibrary + false + true + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + ..\Toolkit.ruleset + false + + + false + ..\Toolkit.ruleset + true + + + false + ..\Toolkit.ruleset + false + + + false + ..\Toolkit.ruleset + true + + + false + ..\Toolkit.ruleset + false + + + false + ..\Toolkit.ruleset + true + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + stdcpplatest + true + Level4 + true + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + stdcpplatest + true + true + Level4 + true + + + Console + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + stdcpplatest + false + Level4 + true + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + stdcpplatest + true + Level4 + true + + + Console + false + + + + + Use + _WINRT_DLL;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + stdcpplatest + false + Level4 + true + + + Console + false + + + + + Use + _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) + pch.h + $(IntDir)pch.pch + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + /bigobj %(AdditionalOptions) + 28204 + stdcpplatest + true + Level4 + true + + + Console + false + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj.filters b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj.filters new file mode 100644 index 00000000000..fb0f85196ea --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + 843e9b69-b3be-436a-8063-712dd68c8c9e + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {68b61fb4-e30f-4e13-a90a-d600506ffe67} + + + {100341cc-ce8e-481d-a525-78892e08dcd8} + + + + + + DirectWriteTextBlock + + + DirectWriteTextBlock + + + DirectWriteTextBlock + + + UniversalWindowsAppPackageFontLoader + + + UniversalWindowsAppPackageFontLoader + + + + + + DirectWriteTextBlock + + + DirectWriteTextBlock + + + DirectWriteTextBlock + + + UniversalWindowsAppPackageFontLoader + + + UniversalWindowsAppPackageFontLoader + + + UniversalWindowsAppPackageFontLoader + + + + + + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Themes/Generic.xaml b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Themes/Generic.xaml new file mode 100644 index 00000000000..8469728a44d --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/Themes/Generic.xaml @@ -0,0 +1,33 @@ + + + + + diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/pch.cpp b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/pch.cpp new file mode 100644 index 00000000000..1fc2c700b11 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/pch.cpp @@ -0,0 +1,5 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "pch.h" diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/pch.h b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/pch.h new file mode 100644 index 00000000000..1df4bb844b5 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.WinRT/pch.h @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +// these are c++/winrt default includes : https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/author-coclasses +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define BEGIN_NAMESPACE_CONTROLS_WINRT namespace Microsoft { namespace Toolkit { namespace Uwp { namespace UI { namespace Controls { namespace WinRT { +#define END_NAMESPACE_CONTROLS_WINRT } } } } } } + +#include "DirectWriteTextBlock\DirectWriteTextBlock.h" + +// it would be nice to run Code Analysis on this project, but the Code Analyzer crashes due to the generated XAML files and apparently can't find pch.h \ No newline at end of file diff --git a/Windows Community Toolkit.sln b/Windows Community Toolkit.sln index afe96a143b7..756b45fb284 100644 --- a/Windows Community Toolkit.sln +++ b/Windows Community Toolkit.sln @@ -93,6 +93,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Co {3DD8AA7C-3569-4E51-992F-0C2257E8878E} = {3DD8AA7C-3569-4E51-992F-0C2257E8878E} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Toolkit.Uwp.UI.Controls.WinRT", "Microsoft.Toolkit.Uwp.UI.Controls.WinRT\Microsoft.Toolkit.Uwp.UI.Controls.WinRT.vcxproj", "{D4C7AC54-826A-4412-8461-A7C7FD86534B}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution UnitTests\UnitTests.Notifications.Shared\UnitTests.Notifications.Shared.projitems*{982cc826-aacd-4855-9075-430bb6ce40a9}*SharedItemsImports = 13 @@ -659,6 +661,28 @@ Global {D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|x64.Build.0 = Release|Any CPU {D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|x86.ActiveCfg = Release|Any CPU {D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|x86.Build.0 = Release|Any CPU + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|ARM.ActiveCfg = Debug|ARM + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|ARM.Build.0 = Debug|ARM + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|x64.ActiveCfg = Debug|x64 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|x64.Build.0 = Debug|x64 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|x86.ActiveCfg = Debug|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Debug|x86.Build.0 = Debug|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|Any CPU.ActiveCfg = Release|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|Any CPU.Build.0 = Release|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|ARM.ActiveCfg = Release|ARM + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|ARM.Build.0 = Release|ARM + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|x64.ActiveCfg = Release|x64 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|x64.Build.0 = Release|x64 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|x86.ActiveCfg = Release|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Native|x86.Build.0 = Release|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|Any CPU.ActiveCfg = Release|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|ARM.ActiveCfg = Release|ARM + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|ARM.Build.0 = Release|ARM + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|x64.ActiveCfg = Release|x64 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|x64.Build.0 = Release|x64 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|x86.ActiveCfg = Release|Win32 + {D4C7AC54-826A-4412-8461-A7C7FD86534B}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -682,6 +706,7 @@ Global {262BB7CE-EF42-4BF7-B90C-107E6CBB57FF} = {096ECFD7-7035-4487-9C87-81DCE9389620} {A122EA02-4DE7-413D-BFBF-AF7DFC668DD6} = {B30036C4-D514-4E5B-A323-587A061772CE} {D4D78CBA-B238-4794-89A0-4F1A2D8FEA97} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC} + {D4C7AC54-826A-4412-8461-A7C7FD86534B} = {F1AFFFA7-28FE-4770-BA48-10D76F3E59BC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5403B0C4-F244-4F73-A35C-FE664D0F4345} diff --git a/build/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.nuspec b/build/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.nuspec new file mode 100644 index 00000000000..ec11aee18d8 --- /dev/null +++ b/build/Microsoft.Toolkit.Uwp.UI.Controls.WinRT.nuspec @@ -0,0 +1,56 @@ + + + + Microsoft.Toolkit.Uwp.UI.Controls.WinRT + $version$ + Windows Community Toolkit WinRT Controls + Microsoft.Toolkit + Microsoft.Toolkit + https://raw.githubusercontent.com/windows-toolkit/WindowsCommunityToolkit/master/build/nuget.png + https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/license.md + https://github.com/windows-toolkit/WindowsCommunityToolkit + true + This library provides WinRT XAML templated controls. It is part of the Windows Community Toolkit. + v5.0 release https://github.com/Microsoft/WindowsCommunityToolkit/releases + (c) .NET Foundation and Contributors. All rights reserved. + UWP Toolkit Windows Controls DirectWriteTextBlock + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file