// Inserts an InkInteropObject at a specified position. private TextPointer InsertInkAtPosition(TextPointer insertionPosition, InkInteropObject inkobject, out UnsafeNativeMethods.TS_TEXTCHANGE change) { int symbolsAddedBefore = 0; int symbolsAddedAfter = 0; // Prepare an insertion position for InlineUIContainer. // As an optimization, shift outside of any formatting tags to avoid // splitting tags below. while (insertionPosition.GetPointerContext(LogicalDirection.Backward) == TextPointerContext.ElementStart && TextSchema.IsFormattingType(insertionPosition.Parent.GetType())) { insertionPosition = insertionPosition.GetNextContextPosition(LogicalDirection.Backward); } while (insertionPosition.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.ElementEnd && TextSchema.IsFormattingType(insertionPosition.Parent.GetType())) { insertionPosition = insertionPosition.GetNextContextPosition(LogicalDirection.Forward); } // If we need to, split the current parent TextElement and prepare // a suitable home for an InlineUIContainer. if (!TextSchema.IsValidParent(insertionPosition.Parent.GetType(), typeof(InlineUIContainer))) { insertionPosition = TextRangeEditTables.EnsureInsertionPosition(insertionPosition, out symbolsAddedBefore, out symbolsAddedAfter); Invariant.Assert(insertionPosition.Parent is Run, "position must be in Run scope"); insertionPosition = TextRangeEdit.SplitElement(insertionPosition); // We need to remember how many symbols were added into addition // to the InlineUIContainer itself. // Account for the two element edges just added. symbolsAddedBefore += 1; symbolsAddedAfter += 1; } // Create an InlineUIContainer. InlineUIContainer inlineUIContainer = new InlineUIContainer(inkobject); change.start = ((ITextPointer)insertionPosition).Offset - symbolsAddedBefore; change.oldEnd = change.start; // Insert it into the insertionPosition. This adds 3 symbols. insertionPosition.InsertTextElement(inlineUIContainer); change.newEnd = change.start + symbolsAddedBefore + inlineUIContainer.SymbolCount + symbolsAddedAfter; // Return a position after the inserted object. return inlineUIContainer.ElementEnd.GetInsertionPosition(LogicalDirection.Forward); }
private void InsertEmbeddedAtPosition(TextPointer position, IComDataObject data, out UnsafeNativeMethods.TS_TEXTCHANGE change) { SecurityHelper.DemandUnmanagedCode(); ITextContainer container; // Get enhanced metafile handle from IOleDataObject. FORMATETC formatetc = new FORMATETC(); STGMEDIUM stgmedium = new STGMEDIUM(); formatetc.cfFormat = NativeMethods.CF_ENHMETAFILE; formatetc.ptd = IntPtr.Zero; formatetc.dwAspect = DVASPECT.DVASPECT_CONTENT; formatetc.lindex = -1; formatetc.tymed = TYMED.TYMED_ENHMF; stgmedium.tymed = TYMED.TYMED_ENHMF; data.GetData(ref formatetc, out stgmedium); if (stgmedium.unionmember == IntPtr.Zero) { throw new COMException(SR.Get(SRID.TextStore_BadObjectData), NativeMethods.E_INVALIDARG); } IntPtr hbitmap = SystemDrawingHelper.ConvertMetafileToHBitmap(stgmedium.unionmember); // create a InkInteropObject framework element. InkInteropObject inkobject = new InkInteropObject(data); inkobject.Source = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, null); position = InsertInkAtPosition(position, inkobject, out change); // Move the selection. container = this.TextContainer; TextSelection.SetCaretToPosition(position, LogicalDirection.Backward, /*allowStopAtLineEnd:*/false, /*allowStopNearSpace:*/false); }