diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/ComplexLine.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/ComplexLine.cs index 569380a63ff..16386871602 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/ComplexLine.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/ComplexLine.cs @@ -160,7 +160,6 @@ internal override void Arrange(VisualCollection vc, Vector lineOffset) Debug.Assert(runs != null, "Cannot retrieve runs collection."); // Calculate offset shift due to trailing spaces - double adjustedXOffset = lineOffset.X + CalculateXOffsetShift(); foreach (TextSpan textSpan in runs) { TextRun run = textSpan.Value; @@ -169,8 +168,7 @@ internal override void Arrange(VisualCollection vc, Vector lineOffset) InlineObject inlineObject = run as InlineObject; // Disconnect visual from its old parent, if necessary. - Visual currentParent = VisualTreeHelper.GetParent(inlineObject.Element) as Visual; - if (currentParent != null) + if (VisualTreeHelper.GetParent(inlineObject.Element) is Visual currentParent) { ContainerVisual parent = currentParent as ContainerVisual; Invariant.Assert(parent != null, "parent should always derives from ContainerVisual"); @@ -178,17 +176,16 @@ internal override void Arrange(VisualCollection vc, Vector lineOffset) } // Get position of inline object withing the text line. - FlowDirection flowDirection; - Rect rect = GetBoundsFromPosition(runDcp, inlineObject.Length, out flowDirection); + Rect rect = GetBoundsFromPosition(runDcp, inlineObject.Length, out FlowDirection flowDirection); Debug.Assert(DoubleUtil.GreaterThanOrClose(rect.Width, 0), "Negative inline object's width."); ContainerVisual proxyVisual = new ContainerVisual(); - if (inlineObject.Element is FrameworkElement) + if (inlineObject.Element is FrameworkElement frameworkElement) { FlowDirection parentFlowDirection = _owner.FlowDirection; // Check parent's FlowDirection to determine if mirroring is needed - DependencyObject parent = ((FrameworkElement)inlineObject.Element).Parent; + DependencyObject parent = frameworkElement.Parent; if(parent != null) { parentFlowDirection = (FlowDirection)parent.GetValue(FrameworkElement.FlowDirectionProperty); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/Line.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/Line.cs index 15fc3bd89c1..87b96e815b5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/Line.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Text/Line.cs @@ -160,10 +160,8 @@ internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection fl /// it uses those as the bounding rectangles. If not, it returns the rectangle for the first (and only) element /// of the text bounds. /// - internal List GetRangeBounds(int cp, int cch, double xOffset, double yOffset) - { - List rectangles = new List(); - + internal ReadOnlySpan GetRangeBounds(int cp, int cch, double xOffset, double yOffset) + { // Adjust x offset for trailing spaces double delta = CalculateXOffsetShift(); double adjustedXOffset = xOffset + delta; @@ -173,7 +171,7 @@ internal List GetRangeBounds(int cp, int cch, double xOffset, double yOffs { // We should not shift offset in this case Invariant.Assert(DoubleUtil.AreClose(delta, 0)); - System.Windows.Media.TextFormatting.TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); + TextLine line = _line.Collapse(GetCollapsingProps(_wrappingWidth, _owner.ParagraphProperties)); Invariant.Assert(line.HasCollapsed, "Line has not been collapsed"); textBounds = line.GetTextBounds(cp, cch); } @@ -181,16 +179,19 @@ internal List GetRangeBounds(int cp, int cch, double xOffset, double yOffs { textBounds = _line.GetTextBounds(cp, cch); } + Invariant.Assert(textBounds.Count > 0); + Rect[] rectangles = new Rect[textBounds.Count]; - for (int boundIndex = 0; boundIndex < textBounds.Count; boundIndex++) + for (int boundIndex = 0; boundIndex < rectangles.Length; boundIndex++) { Rect rect = textBounds[boundIndex].Rectangle; rect.X += adjustedXOffset; rect.Y += yOffset; - rectangles.Add(rect); + rectangles[boundIndex] = rect; } + return rectangles; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs index 21677df16fe..b654e96f74c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/HostedElements.cs @@ -6,14 +6,10 @@ // Enumerator class for returning descendants of TextBlock and FlowDocumentPage // +using System.Diagnostics; using System.Collections; -using MS.Internal.Documents; using System.Collections.Generic; using System.Collections.ObjectModel; -using System; -using System.Diagnostics; - -#pragma warning disable 1634, 1691 // suppressing PreSharp warnings namespace System.Windows.Documents { @@ -21,7 +17,7 @@ namespace System.Windows.Documents /// Enumerator class for implementation of IContentHost on TextBlock and FlowDocumentPage. /// Used to iterate through descendants of the content host /// - internal class HostedElements : IEnumerator + internal sealed class HostedElements : IEnumerator { //------------------------------------------------------------------- // @@ -164,19 +160,13 @@ public IInputElement Current { get { - // Disable PRESharp warning 6503: "Property get methods should not throw exceptions". - // HostedElements must throw exception if Current property is incorrectly accessed if (_textSegments == null) { - // Collection was modified -#pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception throw new InvalidOperationException(SR.EnumeratorCollectionDisposed); } if (_currentPosition == null) { - // Enumerator not started. Call MoveNext to see if we can move ahead -#pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception throw new InvalidOperationException(SR.EnumeratorNotStarted); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs index 72c1e1cd5d7..f219f1df09f 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs @@ -337,25 +337,16 @@ static TextBlock() /// /// Initializes a new instance of TextBlock class. /// - public TextBlock() : base() - { - Initialize(); - } + public TextBlock() : base() { } /// /// Initializes a new inslace of TextBlock class and adds a first Inline to its Inline collection. /// - public TextBlock(Inline inline) - : base() + public TextBlock(Inline inline) : base() { - Initialize(); ArgumentNullException.ThrowIfNull(inline); - this.Inlines.Add(inline); - } - - private void Initialize() - { + Inlines.Add(inline); } #endregion Constructors @@ -1161,7 +1152,7 @@ protected override Visual GetVisualChild(int index) { if (_complexContent == null) { - throw new ArgumentOutOfRangeException("index"); + throw new ArgumentOutOfRangeException(nameof(index)); } return _complexContent.VisualChildren[index]; } @@ -1198,7 +1189,7 @@ protected sealed override Size MeasureOverride(Size constraint) // a) content is dirty (properties or content) // b) there are inline objects (they may be dynamically sized) int lineCount = LineCount; - if ((lineCount > 0) && IsMeasureValid && InlineObjects == null) + if ((lineCount > 0) && IsMeasureValid && InlineObjects is null) { // Assuming that all of above conditions are true, Measure can be // skipped in following situations: @@ -1286,7 +1277,7 @@ protected sealed override Size MeasureOverride(Size constraint) // paragraph ellipsis at this time. Since TextBlock is auto-sized we do not know the RenderSize until we finish Measure line.Format(dcp, contentSize.Width, GetLineProperties(dcp == 0, lineProperties), textLineBreakIn, _textBlockCache._textRunCache, /*Show paragraph ellipsis*/ false); - double lineHeight = CalcLineAdvance(line.Height, lineProperties); + double lineHeight = CalcLineAdvance(lineProperties, line.Height); #if DEBUG LineMetrics metrics = new LineMetrics(contentSize.Width, line.Length, line.Width, lineHeight, line.BaselineOffset, line.HasInlineObjects(), textLineBreakIn); @@ -1397,9 +1388,9 @@ protected sealed override Size ArrangeOverride(Size arrangeSize) _complexContent.VisualChildren.Clear(); } - ArrayList inlineObjects = InlineObjects; + List inlineObjects = InlineObjects; int lineCount = LineCount; - if (inlineObjects != null && lineCount > 0) + if (inlineObjects is not null && lineCount > 0) { bool exceptionThrown = true; @@ -1423,7 +1414,7 @@ protected sealed override Size ArrangeOverride(Size arrangeSize) for (int i = 0; i < lineCount; i++) { -Debug.Assert(lineCount == LineCount); + Debug.Assert(lineCount == LineCount); LineMetrics lineMetrics = GetLine(i); if (lineMetrics.HasInlineObjects) @@ -1662,7 +1653,8 @@ protected sealed override HitTestResult HitTestCore(PointHitTestParameters hitTe protected virtual IInputElement InputHitTestCore(Point point) { // If layout data is not updated return 'this'. - if (!IsLayoutDataValid) { return this; } + if (!IsLayoutDataValid) + return this; // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing. LineProperties lineProperties = GetLineProperties(); @@ -1672,23 +1664,23 @@ protected virtual IInputElement InputHitTestCore(Point point) // a) use cached line information to find which line has been hit, // b) re-create the line that has been hit, // c) hit-test the line. - IInputElement ie = null; double wrappingWidth = CalcWrappingWidth(RenderSize.Width); Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth); point -= contentOffset; // // Take into account content offset. - if (point.X < 0 || point.Y < 0) return this; + if (point.X < 0 || point.Y < 0) + return this; - ie = null; + IInputElement ie = null; int dcp = 0; double lineOffset = 0; - TextRunCache textRunCache = new TextRunCache(); + TextRunCache textRunCache = new(); int lineCount = LineCount; for (int i = 0; i < lineCount; i++) { -Debug.Assert(lineCount == LineCount); + Debug.Assert(lineCount == LineCount); LineMetrics lineMetrics = GetLine(i); if (lineOffset + lineMetrics.Height > point.Y) @@ -1727,7 +1719,7 @@ protected virtual IInputElement InputHitTestCore(Point point) } // If nothing has been hit, assume that element itself has been hit. - return (ie != null) ? ie : this; + return ie ?? this; } /// @@ -1747,7 +1739,7 @@ protected virtual ReadOnlyCollection GetRectanglesCore(ContentElement chil if (!IsLayoutDataValid) { // return empty collection - return new ReadOnlyCollection(new List(0)); + return ReadOnlyCollection.Empty; } // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing. @@ -1757,20 +1749,20 @@ protected virtual ReadOnlyCollection GetRectanglesCore(ContentElement chil if (_complexContent == null || !(_complexContent.TextContainer is TextContainer)) { // return empty collection - return new ReadOnlyCollection(new List(0)); + return ReadOnlyCollection.Empty; } // First find the element start and end position - TextPointer start = FindElementPosition((IInputElement)child); + TextPointer start = FindElementPosition(child); if (start == null) { - return new ReadOnlyCollection(new List(0)); + return ReadOnlyCollection.Empty; } TextPointer end = null; - if (child is TextElement) + if (child is TextElement element) { - end = new TextPointer(((TextElement)child).ElementEnd); + end = new TextPointer(element.ElementEnd); } else if (child is FrameworkContentElement) { @@ -1780,7 +1772,7 @@ protected virtual ReadOnlyCollection GetRectanglesCore(ContentElement chil if (end == null) { - return new ReadOnlyCollection(new List(0)); + return ReadOnlyCollection.Empty; } int startOffset = _complexContent.TextContainer.Start.GetOffsetToPosition(start); @@ -1835,8 +1827,8 @@ protected virtual ReadOnlyCollection GetRectanglesCore(ContentElement chil double xOffset = contentOffset.X; double yOffset = contentOffset.Y + lineHeightOffset; - List lineBounds = line.GetRangeBounds(boundStart, boundEnd - boundStart, xOffset, yOffset); - Debug.Assert(lineBounds.Count > 0); + ReadOnlySpan lineBounds = line.GetRangeBounds(boundStart, boundEnd - boundStart, xOffset, yOffset); + Debug.Assert(lineBounds.Length > 0); rectangles.AddRange(lineBounds); } } @@ -1859,26 +1851,22 @@ protected virtual IEnumerator HostedElementsCore { get { - if(CheckFlags(Flags.ContentChangeInProgress)) + if (CheckFlags(Flags.ContentChangeInProgress)) { - #pragma warning suppress 6503 // IEnumerator.Current is documented to throw this exception throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid); } if (_complexContent == null || !(_complexContent.TextContainer is TextContainer)) { // Return empty collection - return new HostedElements(new ReadOnlyCollection(new List(0))); + return new HostedElements(ReadOnlyCollection.Empty); } // Create a TextSegment from TextContainer, use it to return enumerator - System.Collections.Generic.List textSegmentsList = new System.Collections.Generic.List(1); - TextSegment textSegment = new TextSegment(_complexContent.TextContainer.Start, _complexContent.TextContainer.End); - textSegmentsList.Insert(0, textSegment); - ReadOnlyCollection textSegments = new ReadOnlyCollection(textSegmentsList); + TextSegment[] textSegment = new TextSegment[1] { new TextSegment(_complexContent.TextContainer.Start, _complexContent.TextContainer.End) }; // Return enumerator created from textSegments - return new HostedElements(textSegments); + return new HostedElements(new ReadOnlyCollection(textSegment)); } } @@ -1981,20 +1969,20 @@ internal Size MeasureChild(InlineObject inlineObject) desiredSize = inlineObject.Element.DesiredSize; // Store inline object in the cache. - ArrayList inlineObjects = InlineObjects; + List inlineObjects = InlineObjects; bool alreadyCached = false; - if (inlineObjects == null) + if (inlineObjects is null) { - InlineObjects = inlineObjects = new ArrayList(1); + InlineObjects = inlineObjects = new List(1); } else { // Find out if inline object is already cached. for (int index = 0; index < inlineObjects.Count; index++) { - if (((InlineObject)inlineObjects[index]).Dcp == inlineObject.Dcp) + if (inlineObjects[index].Dcp == inlineObject.Dcp) { - Debug.Assert(((InlineObject)inlineObjects[index]).Element == inlineObject.Element, "InlineObject cache is out of sync."); + Debug.Assert(inlineObjects[index].Element == inlineObject.Element, "InlineObject cache is out of sync."); alreadyCached = true; break; } @@ -2325,7 +2313,7 @@ internal Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPo if (Invariant.Strict) { // Check consistency of line formatting - MS.Internal.Invariant.Assert(GetLine(i).Length == line.Length, "Line length is out of sync"); + Invariant.Assert(GetLine(i).Length == line.Length, "Line length is out of sync"); } int dcpStart = Math.Max(dcpLineStart, dcpPositionStart); @@ -2333,28 +2321,24 @@ internal Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPo if (dcpStart != dcpEnd) { - IList aryTextBounds = line.GetRangeBounds(dcpStart, dcpEnd - dcpStart, contentOffset.X, contentOffset.Y + lineOffset); - - if (aryTextBounds.Count > 0) + ReadOnlySpan aryTextBounds = line.GetRangeBounds(dcpStart, dcpEnd - dcpStart, contentOffset.X, contentOffset.Y + lineOffset); + if (!aryTextBounds.IsEmpty) { - int j = 0; - int c = aryTextBounds.Count; + // Process the bounds minus the last one + for (int j = 0; j < aryTextBounds.Length - 1; j++) + { + CaretElement.AddGeometry(ref geometry, new RectangleGeometry(aryTextBounds[j])); + } - do + // Process the last bounds entry + Rect lastRect = aryTextBounds[aryTextBounds.Length - 1]; + if (dcpPositionEnd >= dcpLineEnd && TextPointerBase.IsNextToAnyBreak(endOfLineTextPointer, LogicalDirection.Backward)) { - Rect rect = aryTextBounds[j]; - - if (j == (c - 1) - && dcpPositionEnd >= dcpLineEnd - && TextPointerBase.IsNextToAnyBreak(endOfLineTextPointer, LogicalDirection.Backward)) - { - double endOfParaGlyphWidth = FontSize * CaretElement.c_endOfParaMagicMultiplier; - rect.Width = rect.Width + endOfParaGlyphWidth; - } - - RectangleGeometry rectGeometry = new RectangleGeometry(rect); - CaretElement.AddGeometry(ref geometry, rectGeometry); - } while (++j < c); + double endOfParaGlyphWidth = FontSize * CaretElement.c_endOfParaMagicMultiplier; + lastRect.Width += endOfParaGlyphWidth; + } + + CaretElement.AddGeometry(ref geometry, new RectangleGeometry(lastRect)); } } } @@ -2781,10 +2765,14 @@ internal bool IsTypographyDefaultValue //------------------------------------------------------------------- // InlineObjects //------------------------------------------------------------------- - private ArrayList InlineObjects + private List InlineObjects { - get { return (_complexContent == null) ? null : _complexContent.InlineObjects; } - set { if (_complexContent != null) _complexContent.InlineObjects = value; } + get => _complexContent?.InlineObjects; + set + { + if (_complexContent is not null) + _complexContent.InlineObjects = value; + } } //------------------------------------------------------------------- @@ -2923,19 +2911,6 @@ private void EnsureComplexContent(ITextContainer textContainer) } } - // ------------------------------------------------------------------ - // Make sure that complex content is cleared. - // ------------------------------------------------------------------ - private void ClearComplexContent() - { - if (_complexContent != null) - { - _complexContent.Detach(this); - _complexContent = null; - Invariant.Assert(_contentCache == null, "Content cache should be null when complex content exists."); - } - } - // ------------------------------------------------------------------ // Invalidates a portion of text affected by a highlight change. // ------------------------------------------------------------------ @@ -3097,7 +3072,7 @@ private TextParagraphProperties GetLineProperties(bool firstLine, bool showParag // // Returns: Line advance distance.. //------------------------------------------------------------------- - private double CalcLineAdvance(double lineHeight, LineProperties lineProperties) + private static double CalcLineAdvance(LineProperties lineProperties, double lineHeight) { return lineProperties.CalcLineAdvance(lineHeight); } @@ -3420,29 +3395,28 @@ private void AlignContent() LineProperties lineProperties = GetLineProperties(); double wrappingWidth = CalcWrappingWidth(RenderSize.Width); - Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth); // Create / format all lines. // Since we are disposing line object, it can be reused to format following lines. Line line = CreateLine(lineProperties); - TextRunCache textRunCache = new TextRunCache(); + TextRunCache textRunCache = new(); int dcp = 0; double lineOffset = 0; int lineCount = LineCount; for (int i = 0; i < lineCount; i++) { -Debug.Assert(lineCount == LineCount); + Debug.Assert(lineCount == LineCount); LineMetrics lineMetrics = GetLine(i); using (line) { bool ellipsis = ParagraphEllipsisShownOnLine(i, lineOffset); Format(line, lineMetrics.Length, dcp, wrappingWidth, GetLineProperties(dcp == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, ellipsis); - double lineHeight = CalcLineAdvance(line.Height, lineProperties); + double lineHeight = CalcLineAdvance(lineProperties, line.Height); // Check consistency of line formatting - MS.Internal.Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of sync"); + Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of sync"); Debug.Assert(DoubleUtil.AreClose(lineHeight, lineMetrics.Height), "Line height is out of sync."); // Calculated line width might be different from measure width in following cases: @@ -3472,10 +3446,7 @@ private void AlignContent() // ------------------------------------------------------------------ private static void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs args) { - TextBlock textBlock = sender as TextBlock; - ContentElement child = args.TargetObject as ContentElement; - - if (textBlock != null && child != null) + if (sender is TextBlock textBlock && args.TargetObject is ContentElement child) { if (TextBlock.ContainsContentElement(textBlock, child)) { @@ -3574,57 +3545,22 @@ private bool CheckFlags(Flags flags) // ------------------------------------------------------------------ private void VerifyReentrancy() { - if(CheckFlags(Flags.MeasureInProgress)) + if (CheckFlags(Flags.MeasureInProgress)) { throw new InvalidOperationException(SR.MeasureReentrancyInvalid); } - if(CheckFlags(Flags.ArrangeInProgress)) + if (CheckFlags(Flags.ArrangeInProgress)) { throw new InvalidOperationException(SR.ArrangeReentrancyInvalid); } - if(CheckFlags(Flags.ContentChangeInProgress)) + if (CheckFlags(Flags.ContentChangeInProgress)) { throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid); } } - /// - /// Returns index of the line that starts at the given dcp. Returns -1 if - /// no line or the line metrics collection starts at the given dcp - /// - /// - /// Start dcp of required line - /// - private int GetLineIndexFromDcp(int dcpLine) - { - Invariant.Assert(dcpLine >= 0); - int lineIndex = 0; - int lineStartOffset = 0; - - int lineCount = LineCount; - while (lineIndex < lineCount) - { -Debug.Assert(lineCount == LineCount); - if (lineStartOffset == dcpLine) - { - // Found line that starts at given dcp - return lineIndex; - } - else - { - lineStartOffset += GetLine(lineIndex).Length; - ++lineIndex; - } - } - - // No line found starting at this position. Return -1. - // We should never hit this code - Invariant.Assert(false, "Dcp passed is not at start of any line in TextBlock"); - return -1; - } - // ------------------------------------------------------------------ // IContentHost Helpers // ------------------------------------------------------------------ @@ -3909,7 +3845,7 @@ private enum Flags //------------------------------------------------------------------- // Represents complex content. //------------------------------------------------------------------- - private class ComplexContent + private sealed class ComplexContent { //--------------------------------------------------------------- // Ctor @@ -3977,7 +3913,7 @@ internal void Detach(TextBlock owner) //--------------------------------------------------------------- // Collection of inline objects hosted by the TextBlock control. //--------------------------------------------------------------- - internal ArrayList InlineObjects; + internal List InlineObjects; } //------------------------------------------------------------------- diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs index 64a21fd7fc3..4426710c23f 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs @@ -478,6 +478,13 @@ internal void UpdateSelection() } } + /// + /// Combines the using + /// with the parameter. In case is , + /// it is only assigned from . In case both are , it's a no-op. + /// + /// The to combine/assign into. + /// The to be combined/assigned. internal static void AddGeometry(ref Geometry geometry, Geometry addedGeometry) { if (addedGeometry != null)