diff --git a/src/samples/DirectDraw/Direct2dDemo/Program.cs b/src/samples/DirectDraw/Direct2dDemo/Program.cs index 58b55a0..fb9a53c 100644 --- a/src/samples/DirectDraw/Direct2dDemo/Program.cs +++ b/src/samples/DirectDraw/Direct2dDemo/Program.cs @@ -4,7 +4,6 @@ using System.Drawing; using System.Numerics; using Windows; -using Windows.Win32.Foundation; using Windows.Win32.Graphics.Direct2D; namespace Direct2dDemo; @@ -23,63 +22,63 @@ public Direct2dDemo() : base(title: "Simple Direct2D Application", features: Fea { } - protected override void RenderTargetCreated(HwndRenderTarget renderTarget) + protected override void RenderTargetCreated() { _lightSlateGrayBrush?.Dispose(); _cornflowerBlueBrush?.Dispose(); - _lightSlateGrayBrush = renderTarget.CreateSolidColorBrush(Color.LightSlateGray); - _cornflowerBlueBrush = renderTarget.CreateSolidColorBrush(Color.CornflowerBlue); - base.RenderTargetCreated(renderTarget); + _lightSlateGrayBrush = RenderTarget.CreateSolidColorBrush(Color.LightSlateGray); + _cornflowerBlueBrush = RenderTarget.CreateSolidColorBrush(Color.CornflowerBlue); + base.RenderTargetCreated(); } - protected override LRESULT WindowProcedure(HWND window, MessageType message, WPARAM wParam, LPARAM lParam) + protected override void OnPaint() { - switch (message) - { - case MessageType.Paint: - if (IsDirect2dEnabled(out var renderTarget)) - { - renderTarget.SetTransform(Matrix3x2.Identity); - renderTarget.Clear(Color.White); + RenderTarget.SetTransform(Matrix3x2.Identity); + RenderTarget.Clear(Color.White); - SizeF size = renderTarget.Size(); + SizeF size = RenderTarget.Size(); - for (int x = 0; x < size.Width; x += 10) - { - renderTarget.DrawLine( - new(x, 0), new(x, size.Height), - _lightSlateGrayBrush!, - 0.5f); - } + for (int x = 0; x < size.Width; x += 10) + { + RenderTarget.DrawLine( + new(x, 0), new(x, size.Height), + _lightSlateGrayBrush!, + 0.5f); + } - for (int y = 0; y < size.Height; y += 10) - { - renderTarget.DrawLine( - new(0, y), new(size.Width, y), - _lightSlateGrayBrush!, - 0.5f); - } + for (int y = 0; y < size.Height; y += 10) + { + RenderTarget.DrawLine( + new(0, y), new(size.Width, y), + _lightSlateGrayBrush!, + 0.5f); + } - RectangleF rectangle1 = RectangleF.FromLTRB( - size.Width / 2 - 50, - size.Height / 2 - 50, - size.Width / 2 + 50, - size.Height / 2 + 50); + RectangleF rectangle1 = RectangleF.FromLTRB( + size.Width / 2 - 50, + size.Height / 2 - 50, + size.Width / 2 + 50, + size.Height / 2 + 50); - RectangleF rectangle2 = RectangleF.FromLTRB( - size.Width / 2 - 100, - size.Height / 2 - 100, - size.Width / 2 + 100, - size.Height / 2 + 100); + RectangleF rectangle2 = RectangleF.FromLTRB( + size.Width / 2 - 100, + size.Height / 2 - 100, + size.Width / 2 + 100, + size.Height / 2 + 100); - renderTarget.FillRectangle(rectangle1, _lightSlateGrayBrush!); - renderTarget.DrawRectangle(rectangle2, _cornflowerBlueBrush!); - } + RenderTarget.FillRectangle(rectangle1, _lightSlateGrayBrush!); + RenderTarget.DrawRectangle(rectangle2, _cornflowerBlueBrush!); + } - return (LRESULT)0; + protected override void Dispose(bool disposing) + { + if (disposing) + { + _lightSlateGrayBrush?.Dispose(); + _cornflowerBlueBrush?.Dispose(); } - return base.WindowProcedure(window, message, wParam, lParam); + base.Dispose(disposing); } } } diff --git a/src/samples/DirectDraw/DirectWriteDemo/DirectWriteDemo.csproj b/src/samples/DirectDraw/DirectWriteDemo/DirectWriteDemo.csproj new file mode 100644 index 0000000..6888128 --- /dev/null +++ b/src/samples/DirectDraw/DirectWriteDemo/DirectWriteDemo.csproj @@ -0,0 +1,11 @@ + + + + WinExe + + + + + + + diff --git a/src/samples/DirectDraw/DirectWriteDemo/Program.cs b/src/samples/DirectDraw/DirectWriteDemo/Program.cs new file mode 100644 index 0000000..8bac399 --- /dev/null +++ b/src/samples/DirectDraw/DirectWriteDemo/Program.cs @@ -0,0 +1,82 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; +using Windows; +using Windows.Win32.Graphics.Direct2D; +using Windows.Win32.Graphics.DirectWrite; +using FontWeight = Windows.Win32.Graphics.DirectWrite.FontWeight; + +namespace DirectWriteDemo; + +internal class Program +{ + [STAThread] + private static void Main() => Application.Run(new DirectWriteDemo()); + + private class DirectWriteDemo : MainWindow + { + private const string Message = "Hello World From ... DirectWrite!"; + + protected TextFormat _textFormat; + protected TextLayout? _textLayout; + protected Typography _typography; + + protected SolidColorBrush? _blackBrush; + + public DirectWriteDemo() : base(title: "Simple DirectWrite Application", features: Features.EnableDirect2d) + { + _textFormat = new("Gabriola", fontSize: 64) + { + TextAlignment = TextAlignment.Center, + ParagraphAlignment = ParagraphAlignment.Center + }; + + _typography = new(); + _typography.AddFontFeature(FontFeatureTag.StylisticSet7); + } + + protected override void RenderTargetCreated() + { + _blackBrush?.Dispose(); + _blackBrush = RenderTarget.CreateSolidColorBrush(Color.Black); + base.RenderTargetCreated(); + } + + protected override void OnPaint() + { + RenderTarget.Clear(Color.CornflowerBlue); + RenderTarget.DrawTextLayout(default, _textLayout!, _blackBrush!); + } + + protected override void OnSize(Size size) + { + if (_textLayout is not null) + { + _textLayout.MaxHeight = size.Height; + _textLayout.MaxWidth = size.Width; + return; + } + + _textLayout = new(Message, _textFormat, RenderTarget.Size()); + + // (21, 12) is the range around "DirectWrite!" + _textLayout.SetFontSize(100, (21, 12)); + _textLayout.SetTypography(_typography, (0, Message.Length)); + _textLayout.SetUnderline(true, (21, 12)); + _textLayout.SetFontWeight(FontWeight.Bold, (21, 12)); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _textFormat.Dispose(); + _textLayout?.Dispose(); + _blackBrush?.Dispose(); + } + + base.Dispose(disposing); + } + } +} diff --git a/src/thirtytwo/Application.cs b/src/thirtytwo/Application.cs index 4dfbf06..e18c500 100644 --- a/src/thirtytwo/Application.cs +++ b/src/thirtytwo/Application.cs @@ -5,13 +5,15 @@ using System.Runtime.InteropServices; using Windows.Support; using Windows.Win32.Graphics.Direct2D; +using Windows.Win32.Graphics.DirectWrite; namespace Windows; public static unsafe class Application { private static ActivationContext? s_visualStylesContext; - private static Factory? s_direct2dFactory; + private static Direct2dFactory? s_direct2dFactory; + private static DirectWriteFactory? s_directWriteFactory; internal static ActivationScope ThemingScope => new(GetStylesContext()); @@ -207,5 +209,6 @@ public static void EnumerateThreadWindows( using var enumerator = new ThreadWindowEnumerator(threadId, callback); } - public static Factory Direct2dFactory => s_direct2dFactory ??= new(); + public static Direct2dFactory Direct2dFactory => s_direct2dFactory ??= new(); + public static DirectWriteFactory DirectWriteFactory => s_directWriteFactory ??= new(); } \ No newline at end of file diff --git a/src/thirtytwo/NativeMethods.txt b/src/thirtytwo/NativeMethods.txt index f7522bf..b8768f6 100644 --- a/src/thirtytwo/NativeMethods.txt +++ b/src/thirtytwo/NativeMethods.txt @@ -350,4 +350,6 @@ WM_* XFORMCOORDS ID2D1Factory D2D1CreateFactory -D2DERR_RECREATE_TARGET \ No newline at end of file +D2DERR_RECREATE_TARGET +DWriteCreateFactory +IDWriteFactory \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/Direct2D/Common/D2D_POINT_F.cs b/src/thirtytwo/Win32/Graphics/Direct2D/Common/D2D_POINT_F.cs new file mode 100644 index 0000000..1d0cd7b --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/Direct2D/Common/D2D_POINT_F.cs @@ -0,0 +1,18 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; + +namespace Windows.Win32.Graphics.Direct2D.Common; + +public partial struct D2D_POINT_2F +{ + public D2D_POINT_2F(float x, float y) + { + this.x = x; + this.y = y; + } + + public static implicit operator D2D_POINT_2F(PointF value) => + new(value.X, value.Y); +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/Direct2D/Factory.cs b/src/thirtytwo/Win32/Graphics/Direct2D/Direct2dFactory.cs similarity index 91% rename from src/thirtytwo/Win32/Graphics/Direct2D/Factory.cs rename to src/thirtytwo/Win32/Graphics/Direct2D/Direct2dFactory.cs index 2303f6c..a8aebcd 100644 --- a/src/thirtytwo/Win32/Graphics/Direct2D/Factory.cs +++ b/src/thirtytwo/Win32/Graphics/Direct2D/Direct2dFactory.cs @@ -6,13 +6,13 @@ namespace Windows.Win32.Graphics.Direct2D; -public unsafe class Factory : DisposableBase.Finalizable, IPointer +public unsafe class Direct2dFactory : DisposableBase.Finalizable, IPointer { private readonly AgileComPointer _factory; public unsafe ID2D1Factory* Pointer { get; private set; } - public Factory( + public Direct2dFactory( D2D1_FACTORY_TYPE factoryType = D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, D2D1_DEBUG_LEVEL factoryOptions = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_NONE) { diff --git a/src/thirtytwo/Win32/Graphics/Direct2D/DrawTextOptions.cs b/src/thirtytwo/Win32/Graphics/Direct2D/DrawTextOptions.cs new file mode 100644 index 0000000..57cd5e1 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/Direct2D/DrawTextOptions.cs @@ -0,0 +1,27 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.Direct2D; + +/// +/// Modifications made to the draw text call that influence how the text is rendered. +/// [] +/// +[Flags] +public enum DrawTextOptions +{ + /// + NoSnap = D2D1_DRAW_TEXT_OPTIONS.D2D1_DRAW_TEXT_OPTIONS_NO_SNAP, + + /// + Clip = D2D1_DRAW_TEXT_OPTIONS.D2D1_DRAW_TEXT_OPTIONS_CLIP, + + /// + EnableColorFont = D2D1_DRAW_TEXT_OPTIONS.D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT, + + /// + DisableColorBitmapSnapping = D2D1_DRAW_TEXT_OPTIONS.D2D1_DRAW_TEXT_OPTIONS_DISABLE_COLOR_BITMAP_SNAPPING, + + /// + None = D2D1_DRAW_TEXT_OPTIONS.D2D1_DRAW_TEXT_OPTIONS_NONE +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/Direct2D/RenderTargetExtensions.cs b/src/thirtytwo/Win32/Graphics/Direct2D/RenderTargetExtensions.cs index f69b11a..2c4b326 100644 --- a/src/thirtytwo/Win32/Graphics/Direct2D/RenderTargetExtensions.cs +++ b/src/thirtytwo/Win32/Graphics/Direct2D/RenderTargetExtensions.cs @@ -5,6 +5,7 @@ using System.Numerics; using Windows.Support; using Windows.Win32.Graphics.Direct2D.Common; +using Windows.Win32.Graphics.DirectWrite; namespace Windows.Win32.Graphics.Direct2D; @@ -92,4 +93,25 @@ public static SizeF Size(this T target) where T : IPointer GC.KeepAlive(target); return *(SizeF*)&size; } + + public static void DrawTextLayout( + this TTarget target, + PointF origin, + TLayout textLayout, + TBrush defaultFillBrush, + DrawTextOptions options = DrawTextOptions.None) + where TTarget : IPointer + where TLayout : IPointer + where TBrush : IPointer + { + target.Pointer->DrawTextLayout( + origin, + textLayout.Pointer, + defaultFillBrush.Pointer, + (D2D1_DRAW_TEXT_OPTIONS)options); + + GC.KeepAlive(target); + GC.KeepAlive(textLayout); + GC.KeepAlive(defaultFillBrush); + } } \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/DirectWriteFactory.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/DirectWriteFactory.cs new file mode 100644 index 0000000..3c6323a --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/DirectWriteFactory.cs @@ -0,0 +1,39 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Windows.Support; +using Windows.Win32.System.Com; + +namespace Windows.Win32.Graphics.DirectWrite; + +public unsafe class DirectWriteFactory : DisposableBase.Finalizable, IPointer +{ + private readonly AgileComPointer _factory; + + public unsafe IDWriteFactory* Pointer { get; private set; } + + public DirectWriteFactory(DWRITE_FACTORY_TYPE factoryType = DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_SHARED) + { + IDWriteFactory* factory; + Interop.DWriteCreateFactory( + factoryType, + IID.Get(), + (void**)&factory).ThrowOnFailure(); + + Pointer = factory; + + // Ensure that this can be disposed on the finalizer thread by giving the "last" ref count + // to an agile pointer. + _factory = new AgileComPointer(factory, takeOwnership: true); + } + + protected override void Dispose(bool disposing) + { + Pointer = null; + + if (disposing) + { + _factory.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/FontFeature.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/FontFeature.cs new file mode 100644 index 0000000..9511781 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/FontFeature.cs @@ -0,0 +1,36 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +public readonly struct FontFeature +{ + /// + /// The feature OpenType name identifier. + /// + public readonly FontFeatureTag NameTag; + + /// + /// Execution parameter of the feature. + /// + /// + /// The parameter should be non-zero to enable the feature. Once enabled, a feature can't be disabled again within + /// the same range. Features requiring a selector use this value to indicate the selector index. + /// + public readonly uint Parameter; + + public FontFeature(FontFeatureTag nameTag, uint parameter) + { + NameTag = nameTag; + Parameter = parameter; + } + + public FontFeature(FontFeatureTag nameTag, bool enable = true) + { + NameTag = nameTag; + Parameter = enable ? 1u : 0u; + } + + public static implicit operator FontFeature(FontFeatureTag tag) => new(tag); +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/FontFeatureTag.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/FontFeatureTag.cs new file mode 100644 index 0000000..a7be1cc --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/FontFeatureTag.cs @@ -0,0 +1,253 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// Typographic feature of text supplied by the font. [] +/// +public enum FontFeatureTag : uint +{ + /// + AlternativeFractions = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ALTERNATIVE_FRACTIONS, + + /// + PetiteCapitalsFromCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PETITE_CAPITALS_FROM_CAPITALS, + + /// + SmallCapitalsFromCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS_FROM_CAPITALS, + + /// + ContextualAlternates = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES, + + /// + CaseSensitiveForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CASE_SENSITIVE_FORMS, + + /// + GlyphCompositionDecomposition = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_GLYPH_COMPOSITION_DECOMPOSITION, + + /// + ContextualLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES, + + /// + CapitalSpacing = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CAPITAL_SPACING, + + /// + ContextualSwash = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_SWASH, + + /// + CursivePositioning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_CURSIVE_POSITIONING, + + /// + Default = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_DEFAULT, + + /// + DiscretionaryLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_DISCRETIONARY_LIGATURES, + + /// + ExpertForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_EXPERT_FORMS, + + /// + Fractions = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_FRACTIONS, + + /// + FullWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_FULL_WIDTH, + + /// + HalfForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HALF_FORMS, + + /// + HalantForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HALANT_FORMS, + + /// + AlternateHalfWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ALTERNATE_HALF_WIDTH, + + /// + HistoricalForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HISTORICAL_FORMS, + + /// + HorizontalKanaAlternates = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HORIZONTAL_KANA_ALTERNATES, + + /// + HistoricalLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HISTORICAL_LIGATURES, + + /// + HalfWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HALF_WIDTH, + + /// + HojoKanjiForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_HOJO_KANJI_FORMS, + + /// + Jis04Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS04_FORMS, + + /// + Jis78Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS78_FORMS, + + /// + Jis83Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS83_FORMS, + + /// + Jis90Forms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_JIS90_FORMS, + + /// + Kerning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_KERNING, + + /// + StandardLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES, + + /// + LiningFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_LINING_FIGURES, + + /// + LocalizedForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_LOCALIZED_FORMS, + + /// + MarkPositioning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_MARK_POSITIONING, + + /// + MathematicalGreek = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_MATHEMATICAL_GREEK, + + /// + MarkToMarkPositioning = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_MARK_TO_MARK_POSITIONING, + + /// + AlternateAnnotationForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ALTERNATE_ANNOTATION_FORMS, + + /// + NlcKanjiForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_NLC_KANJI_FORMS, + + /// + OldStyleFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_OLD_STYLE_FIGURES, + + /// + Ordinals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_ORDINALS, + + /// + ProportionalAlternateWidth = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_ALTERNATE_WIDTH, + + /// + PetiteCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PETITE_CAPITALS, + + /// + ProportionalFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_FIGURES, + + /// + ProportionalWidths = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_WIDTHS, + + /// + QuarterWidths = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_QUARTER_WIDTHS, + + /// + RequiredLigatures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_REQUIRED_LIGATURES, + + /// + RubyNotationForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_RUBY_NOTATION_FORMS, + + /// + StylisticAlternates = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_ALTERNATES, + + /// + ScientificInferiors = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SCIENTIFIC_INFERIORS, + + /// + SmallCapitals = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS, + + /// + SimplifiedForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SIMPLIFIED_FORMS, + + /// + StylisticSet1 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_1, + + /// + StylisticSet2 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_2, + + /// + StylisticSet3 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_3, + + /// + StylisticSet4 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_4, + + /// + StylisticSet5 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_5, + + /// + StylisticSet6 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_6, + + /// + StylisticSet7 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7, + + /// + StylisticSet8 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_8, + + /// + StylisticSet9 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_9, + + /// + StylisticSet10 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_10, + + /// + StylisticSet11 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_11, + + /// + StylisticSet12 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_12, + + /// + StylisticSet13 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_13, + + /// + StylisticSet14 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_14, + + /// + StylisticSet15 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_15, + + /// + StylisticSet16 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_16, + + /// + StylisticSet17 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_17, + + /// + StylisticSet18 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_18, + + /// + StylisticSet19 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_19, + + /// + StylisticSet20 = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_20, + + /// + Subscript = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SUBSCRIPT, + + /// + Superscript = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SUPERSCRIPT, + + /// + Swash = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SWASH, + + /// + Titling = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TITLING, + + /// + TraditionalNameForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TRADITIONAL_NAME_FORMS, + + /// + TabularFigures = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TABULAR_FIGURES, + + /// + TraditionalForms = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_TRADITIONAL_FORMS, + + /// + ThirdWidths = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_THIRD_WIDTHS, + + /// + Unicase = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_UNICASE, + + /// + VerticalWriting = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING, + + /// + VerticalAlternatesAndRotation = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_VERTICAL_ALTERNATES_AND_ROTATION, + + /// + SlashedZero = DWRITE_FONT_FEATURE_TAG.DWRITE_FONT_FEATURE_TAG_SLASHED_ZERO, +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/FontStretch.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/FontStretch.cs new file mode 100644 index 0000000..61147ca --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/FontStretch.cs @@ -0,0 +1,44 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// The font stretch enumeration describes relative change from the normal aspect ratio as specified by a font +/// designer for the glyphs in a font. [] +/// +/// +/// Values less than 1 or greater than 9 are considered to be invalid, and they are rejected by font API functions. +/// +public enum FontStretch : uint +{ + /// + Undefined = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_UNDEFINED, + + /// + UltraCondensed = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_ULTRA_CONDENSED, + + /// + ExtraCondensed = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_EXTRA_CONDENSED, + + /// + Condensed = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_CONDENSED, + + /// + SemiCondensed = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_SEMI_CONDENSED, + + /// + Normal = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL, + + /// + SemiExpanded = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_SEMI_EXPANDED, + + /// + Expanded = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_EXPANDED, + + /// + ExtraExpanded = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_EXTRA_EXPANDED, + + /// + UltraExpanded = DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_ULTRA_EXPANDED +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/FontStyle.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/FontStyle.cs new file mode 100644 index 0000000..44996f8 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/FontStyle.cs @@ -0,0 +1,20 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// The font style enumeration describes the slope style of a font face, such as Normal, Italic or Oblique. +/// [] +/// +public enum FontStyle : uint +{ + /// + Normal = DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL, + + /// + Oblique = DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_OBLIQUE, + + /// + Italic = DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_ITALIC +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/FontWeight.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/FontWeight.cs new file mode 100644 index 0000000..7de5f36 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/FontWeight.cs @@ -0,0 +1,47 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// The font weight enumeration describes common values for degree of blackness or thickness of strokes of characters in a font. +/// [] +/// +/// +/// Font weight values less than 1 or greater than 999 are considered to be invalid, and they are rejected by font API functions. +/// +public enum FontWeight : uint +{ + /// + Thin = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_THIN, + + /// + ExtraLight = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_EXTRA_LIGHT, + + /// + Light = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_LIGHT, + + /// + SemiLight = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_SEMI_LIGHT, + + /// + Normal = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL, + + /// + Medium = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_MEDIUM, + + /// + SemiBold = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_SEMI_BOLD, + + /// + Bold = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_BOLD, + + /// + ExtraBold = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_EXTRA_BOLD, + + /// + Black = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_BLACK, + + /// + ExtraBlack = DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_EXTRA_BLACK, +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/ParagraphAlignment.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/ParagraphAlignment.cs new file mode 100644 index 0000000..dd9a9ac --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/ParagraphAlignment.cs @@ -0,0 +1,20 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// Alignment of paragraph text along the flow direction axis relative to the +/// flow's beginning and ending edge of the layout box. +/// +public enum ParagraphAlignment : uint +{ + /// + Near = DWRITE_PARAGRAPH_ALIGNMENT.DWRITE_PARAGRAPH_ALIGNMENT_NEAR, + + /// + Far = DWRITE_PARAGRAPH_ALIGNMENT.DWRITE_PARAGRAPH_ALIGNMENT_FAR, + + /// + Center = DWRITE_PARAGRAPH_ALIGNMENT.DWRITE_PARAGRAPH_ALIGNMENT_CENTER +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/TextAlignment.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/TextAlignment.cs new file mode 100644 index 0000000..94c95ba --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/TextAlignment.cs @@ -0,0 +1,23 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// Alignment of paragraph text along the reading direction axis relative to +/// the leading and trailing edge of the layout box. [] +/// +public enum TextAlignment : uint +{ + /// + Leading = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_LEADING, + + /// + Trailing = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_TRAILING, + + /// + Center = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_CENTER, + + /// + Justified = DWRITE_TEXT_ALIGNMENT.DWRITE_TEXT_ALIGNMENT_JUSTIFIED +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/TextFormat.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/TextFormat.cs new file mode 100644 index 0000000..f5d77ed --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/TextFormat.cs @@ -0,0 +1,99 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Windows.Support; +using Windows.Win32.System.Com; + +namespace Windows.Win32.Graphics.DirectWrite; + +public unsafe class TextFormat : DisposableBase.Finalizable, IPointer +{ + private readonly AgileComPointer _format; + + public unsafe IDWriteTextFormat* Pointer { get; private set; } + + public TextFormat(IDWriteTextFormat* format) + { + Pointer = format; + + // Ensure that this can be disposed on the finalizer thread by giving the "last" ref count + // to an agile pointer. + _format = new AgileComPointer(format, takeOwnership: true); + } + + public TextFormat( + string fontFamilyName, + float fontSize, + FontWeight fontWeight = FontWeight.Normal, + FontStyle fontStyle = FontStyle.Normal, + FontStretch fontStretch = FontStretch.Normal, + string localeName = "en-us") : this(Create(fontFamilyName, fontSize, fontWeight, fontStyle, fontStretch, localeName)) + { + } + + private static IDWriteTextFormat* Create( + string fontFamilyName, + float fontSize, + FontWeight fontWeight, + FontStyle fontStyle, + FontStretch fontStretch, + string localeName) + { + IDWriteTextFormat* format; + + fixed (char* fn = fontFamilyName) + { + Application.DirectWriteFactory.Pointer->CreateTextFormat( + fontFamilyName, + null, + (DWRITE_FONT_WEIGHT)fontWeight, + (DWRITE_FONT_STYLE)fontStyle, + (DWRITE_FONT_STRETCH)fontStretch, + fontSize, + localeName, + &format).ThrowOnFailure(); + } + + return format; + } + + public TextAlignment TextAlignment + { + get + { + TextAlignment alignment = (TextAlignment)Pointer->GetTextAlignment(); + GC.KeepAlive(this); + return alignment; + } + set + { + Pointer->SetTextAlignment((DWRITE_TEXT_ALIGNMENT)value).ThrowOnFailure(); + GC.KeepAlive(this); + } + } + + public ParagraphAlignment ParagraphAlignment + { + get + { + ParagraphAlignment alignment = (ParagraphAlignment)Pointer->GetParagraphAlignment(); + GC.KeepAlive(this); + return alignment; + } + set + { + Pointer->SetParagraphAlignment((DWRITE_PARAGRAPH_ALIGNMENT)value).ThrowOnFailure(); + GC.KeepAlive(this); + } + } + + protected override void Dispose(bool disposing) + { + Pointer = null; + + if (disposing) + { + _format.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/TextLayout.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/TextLayout.cs new file mode 100644 index 0000000..2a38821 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/TextLayout.cs @@ -0,0 +1,156 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; +using Windows.Support; +using Windows.Win32.System.Com; + +namespace Windows.Win32.Graphics.DirectWrite; + +public unsafe class TextLayout : DisposableBase.Finalizable, IPointer +{ + private readonly AgileComPointer _layout; + + public unsafe IDWriteTextLayout* Pointer { get; private set; } + + public TextLayout(IDWriteTextLayout* layout) + { + Pointer = layout; + + // Ensure that this can be disposed on the finalizer thread by giving the "last" ref count + // to an agile pointer. + _layout = new AgileComPointer(layout, takeOwnership: true); + } + + public TextLayout( + string text, + TextFormat format, + SizeF maxSize) : this(Create(text, format, maxSize.Width, maxSize.Height)) + { + } + + public TextLayout( + string text, + TextFormat format, + float maxWidth, + float maxHeight) : this(Create(text, format, maxWidth, maxHeight)) + { + } + + private static IDWriteTextLayout* Create( + string text, + TextFormat format, + float maxWidth, + float maxHeight) + { + IDWriteTextLayout* layout; + + fixed (char* t = text) + { + Application.DirectWriteFactory.Pointer->CreateTextLayout( + text, + (uint)text.Length, + format.Pointer, + maxWidth, + maxHeight, + &layout).ThrowOnFailure(); + } + + return layout; + } + + public void SetFontSize(float fontSize, TextRange textRange) + { + Pointer->SetFontSize(fontSize, textRange); + GC.KeepAlive(this); + } + + public float MaxWidth + { + get + { + float maxWidth = Pointer->GetMaxWidth(); + GC.KeepAlive(this); + return maxWidth; + } + set + { + Pointer->SetMaxWidth(value); + GC.KeepAlive(this); + } + } + + public float MaxHeight + { + get + { + float maxHeight = Pointer->GetMaxHeight(); + GC.KeepAlive(this); + return maxHeight; + } + set + { + Pointer->SetMaxHeight(value); + GC.KeepAlive(this); + } + } + + public TextAlignment TextAlignment + { + get + { + TextAlignment alignment = (TextAlignment)Pointer->GetTextAlignment(); + GC.KeepAlive(this); + return alignment; + } + set + { + Pointer->SetTextAlignment((DWRITE_TEXT_ALIGNMENT)value); + GC.KeepAlive(this); + } + } + + public ParagraphAlignment ParagraphAlignment + { + get + { + ParagraphAlignment alignment = (ParagraphAlignment)Pointer->GetParagraphAlignment(); + GC.KeepAlive(this); + return alignment; + } + set + { + Pointer->SetParagraphAlignment((DWRITE_PARAGRAPH_ALIGNMENT)value); + GC.KeepAlive(this); + } + } + + public void SetTypography(T typography, TextRange textRange) where T : IPointer + { + Pointer->SetTypography(typography.Pointer, textRange); + GC.KeepAlive(this); + GC.KeepAlive(typography); + } + + public void SetUnderline(bool hasUnderline, TextRange textRange) + { + Pointer->SetUnderline(hasUnderline, textRange); + GC.KeepAlive(this); + } + + public void SetFontWeight(FontWeight fontWeight, TextRange textRange) + { + Pointer->SetFontWeight((DWRITE_FONT_WEIGHT)fontWeight, textRange); + GC.KeepAlive(this); + } + + protected override void Dispose(bool disposing) + { + Pointer = null; + + if (disposing) + { + _layout.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/TextRange.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/TextRange.cs new file mode 100644 index 0000000..8330484 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/TextRange.cs @@ -0,0 +1,35 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; + +namespace Windows.Win32.Graphics.DirectWrite; + +/// +/// Specifies a range of text positions where format is applied. +/// [] +/// +public unsafe readonly struct TextRange +{ + /// + /// The start text position of the range. + /// + public readonly uint StartPosition; + + /// + /// The number of text positions in the range. + /// + public readonly uint Length; + + public TextRange(uint startPosition, uint length) + { + StartPosition = startPosition; + Length = length; + } + + public static implicit operator TextRange((int StartPosition, int Length) tuple) + => new((uint)tuple.StartPosition, (uint)tuple.Length); + + public static implicit operator DWRITE_TEXT_RANGE(TextRange range) => + Unsafe.As(ref range); +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/Graphics/DirectWrite/Typography.cs b/src/thirtytwo/Win32/Graphics/DirectWrite/Typography.cs new file mode 100644 index 0000000..7d16526 --- /dev/null +++ b/src/thirtytwo/Win32/Graphics/DirectWrite/Typography.cs @@ -0,0 +1,73 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.CompilerServices; +using Windows.Support; +using Windows.Win32.System.Com; + +namespace Windows.Win32.Graphics.DirectWrite; + +public unsafe class Typography : DisposableBase.Finalizable, IPointer +{ + private readonly AgileComPointer _typography; + + public unsafe IDWriteTypography* Pointer { get; private set; } + + public Typography(IDWriteTypography* typography) + { + Pointer = typography; + + // Ensure that this can be disposed on the finalizer thread by giving the "last" ref count + // to an agile pointer. + _typography = new AgileComPointer(typography, takeOwnership: true); + } + + public Typography() : this(Create()) + { + } + + private static IDWriteTypography* Create() + { + IDWriteTypography* typography; + Application.DirectWriteFactory.Pointer->CreateTypography(&typography).ThrowOnFailure(); + return typography; + } + + /// + public void AddFontFeature(FontFeature fontFeature) + { + Pointer->AddFontFeature(Unsafe.As(ref fontFeature)).ThrowOnFailure(); + GC.KeepAlive(this); + } + + /// + public void GetFontFeature(uint fontFeatureIndex, out FontFeature fontFeature) + { + fixed (void* f = &fontFeature) + { + Pointer->GetFontFeature(fontFeatureIndex, (DWRITE_FONT_FEATURE*)f); + GC.KeepAlive(this); + } + } + + /// + public uint FontFeatureCount + { + get + { + uint result = Pointer->GetFontFeatureCount(); + GC.KeepAlive(this); + return result; + } + } + + protected override void Dispose(bool disposing) + { + Pointer = null; + + if (disposing) + { + _typography.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/thirtytwo/Window.Features.cs b/src/thirtytwo/Window.Features.cs new file mode 100644 index 0000000..7a24d41 --- /dev/null +++ b/src/thirtytwo/Window.Features.cs @@ -0,0 +1,16 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows; + +public unsafe partial class Window +{ + [Flags] + public enum Features + { + /// + /// Set this flag to enable Direct2D rendering. + /// + EnableDirect2d = 0b0000_0000_0000_0000_0000_0000_0000_0001, + } +} \ No newline at end of file diff --git a/src/thirtytwo/Window.cs b/src/thirtytwo/Window.cs index 9286e4b..8d15882 100644 --- a/src/thirtytwo/Window.cs +++ b/src/thirtytwo/Window.cs @@ -10,7 +10,7 @@ namespace Windows; -public unsafe class Window : ComponentBase, IHandle, ILayoutHandler +public unsafe partial class Window : ComponentBase, IHandle, ILayoutHandler { private static readonly object s_lock = new(); private static readonly ConcurrentDictionary> s_windows = new(); @@ -46,18 +46,20 @@ public unsafe class Window : ComponentBase, IHandle, ILayoutHandler private readonly HBRUSH _backgroundBrush; - protected HwndRenderTarget? Direct2dRenderTarget { get; private set; } + private HwndRenderTarget? _renderTarget; + + protected HwndRenderTarget RenderTarget => _renderTarget ?? throw new InvalidOperationException(); private string? _text; private uint _lastDpi; private readonly Features _features; - [MemberNotNullWhen(true, nameof(Direct2dRenderTarget))] + [MemberNotNullWhen(true, nameof(_renderTarget))] protected bool IsDirect2dEnabled() { bool enabled = _features.AreFlagsSet(Features.EnableDirect2d); - if (enabled && Direct2dRenderTarget is null) + if (enabled && _renderTarget is null) { UpdateRenderTarget(Handle, this.GetClientRectangle().Size); } @@ -65,13 +67,6 @@ protected bool IsDirect2dEnabled() return enabled; } - [MemberNotNullWhen(true, nameof(Direct2dRenderTarget))] - protected bool IsDirect2dEnabled([NotNullWhen(true)] out HwndRenderTarget? renderTarget) - { - renderTarget = Direct2dRenderTarget; - return IsDirect2dEnabled(); - } - /// /// The window handle. This will be after the window is destroyed. /// @@ -186,24 +181,31 @@ public void SetFont(string typeFace, int pointSize) this.SetFontHandle(_lastCreatedFont); } - [MemberNotNull(nameof(Direct2dRenderTarget))] private void UpdateRenderTarget(HWND window, Size size) { - if (Direct2dRenderTarget is null) + if (_renderTarget is null) { - Direct2dRenderTarget = HwndRenderTarget.CreateForWindow(Application.Direct2dFactory, window, size); - RenderTargetCreated(Direct2dRenderTarget); + _renderTarget = HwndRenderTarget.CreateForWindow(Application.Direct2dFactory, window, size); + RenderTargetCreated(); } else { - Direct2dRenderTarget.Resize(size); + _renderTarget.Resize(size); } } /// /// Called whenever the Direct2D render target has been created or recreated. /// - protected virtual void RenderTargetCreated(HwndRenderTarget renderTarget) + protected virtual void RenderTargetCreated() + { + } + + protected virtual void OnPaint() + { + } + + protected virtual void OnSize(Size size) { } @@ -242,20 +244,26 @@ private LRESULT WindowProcedureInternal(HWND window, uint message, WPARAM wParam break; case Interop.WM_SIZE: + Size size = new(lParam.LOWORD, lParam.HIWORD); + // Check the flag directly here so we don't create then resize. if (_features.AreFlagsSet(Features.EnableDirect2d)) { - UpdateRenderTarget(window, new Size(lParam.LOWORD, lParam.HIWORD)); + UpdateRenderTarget(window, size); } + OnSize(size); + break; case Interop.WM_PAINT: - if (IsDirect2dEnabled(out var renderTarget)) + if (IsDirect2dEnabled()) { - renderTarget.BeginDraw(); + _renderTarget.BeginDraw(); } + OnPaint(); + break; } @@ -275,11 +283,11 @@ private LRESULT WindowProcedureInternal(HWND window, uint message, WPARAM wParam if (message == Interop.WM_PAINT && IsDirect2dEnabled()) { - Direct2dRenderTarget.EndDraw(out bool recreateTarget); + _renderTarget.EndDraw(out bool recreateTarget); if (recreateTarget) { - Direct2dRenderTarget.Dispose(); - Direct2dRenderTarget = null; + _renderTarget.Dispose(); + _renderTarget = null; UpdateRenderTarget(window, this.GetClientRectangle().Size); } } @@ -526,13 +534,4 @@ private static WNDPROC GetDefaultWindowProcedure() Debug.Assert(!address.IsNull); return (WNDPROC)(void*)address.Value; } - - [Flags] - public enum Features - { - /// - /// Set this flag to enable Direct2D rendering. - /// - EnableDirect2d = 0b0000_0000_0000_0000_0000_0000_0000_0001, - } } \ No newline at end of file diff --git a/thirtytwo.sln b/thirtytwo.sln index 5dd6b4e..62b8a8e 100644 --- a/thirtytwo.sln +++ b/thirtytwo.sln @@ -59,6 +59,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DirectDraw", "DirectDraw", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct2dDemo", "src\samples\DirectDraw\Direct2dDemo\Direct2dDemo.csproj", "{1EC566E8-C337-42FF-9BA4-DB66BFAE5B8A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DirectWriteDemo", "src\samples\DirectDraw\DirectWriteDemo\DirectWriteDemo.csproj", "{24BAE093-7546-4ED1-AF5C-2A62AD244C63}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -145,6 +147,10 @@ Global {1EC566E8-C337-42FF-9BA4-DB66BFAE5B8A}.Debug|x64.Build.0 = Debug|x64 {1EC566E8-C337-42FF-9BA4-DB66BFAE5B8A}.Release|x64.ActiveCfg = Release|x64 {1EC566E8-C337-42FF-9BA4-DB66BFAE5B8A}.Release|x64.Build.0 = Release|x64 + {24BAE093-7546-4ED1-AF5C-2A62AD244C63}.Debug|x64.ActiveCfg = Debug|x64 + {24BAE093-7546-4ED1-AF5C-2A62AD244C63}.Debug|x64.Build.0 = Debug|x64 + {24BAE093-7546-4ED1-AF5C-2A62AD244C63}.Release|x64.ActiveCfg = Release|x64 + {24BAE093-7546-4ED1-AF5C-2A62AD244C63}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -170,6 +176,7 @@ Global {D4EA97FD-45D3-4A26-843F-63427F0F1BFE} = {13110246-EBE1-441B-B721-B0614D62B13B} {7107A105-51E2-46EB-859D-E2DD2FD51839} = {C059056C-D771-4CF5-A93F-AA7140FF7827} {1EC566E8-C337-42FF-9BA4-DB66BFAE5B8A} = {7107A105-51E2-46EB-859D-E2DD2FD51839} + {24BAE093-7546-4ED1-AF5C-2A62AD244C63} = {7107A105-51E2-46EB-859D-E2DD2FD51839} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3761BFC9-DBEF-4186-BB8B-BC0D84ED9AE5}