private static void MoveUnitBounded(MarkupPointer p, MoveDirection direction, MoveContextFilter continueFilter, MarkupPointer boundary) { MarkupPointer p1 = p.Clone(); MarkupPointer lastGoodPosition = p.Clone(); MarkupContext context = new MarkupContext(); MoveFilterResult result = MoveFilterResult.CONTINUE; while (CheckMoveBoundary(p1, boundary, direction) && result == MoveFilterResult.CONTINUE) { lastGoodPosition.MoveToPointer(p1); MovePointer(p1, direction, context); result = continueFilter(context); } if (result == MoveFilterResult.CONTINUE) { //we hit the boundary, so position pointer at the boundary p1.MoveToPointer(boundary); } else if (result == MoveFilterResult.STOP_BACK) { p1.MoveToPointer(lastGoodPosition); } p.MoveToPointer(p1); }
public static void MoveUnitBounded(MarkupPointer p, MoveDirection direction, MarkupPointerAdjacency stopRule, IHTMLElement boundary) { MarkupPointer pBoundary = p.Clone(); pBoundary.MoveAdjacentToElement(boundary, direction == MoveDirection.LEFT ? _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin : _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd); MoveUnitBounded(p, direction, stopRule, pBoundary); }
/// <summary> /// Walk through the markup range in reverse, letting the walker visit each position. /// </summary> /// <param name="walker">the delegate walking navigating the the markup range</param> /// <param name="inScopeElementsOnly">if true, enter/exit notifications about out-of-scope elements will be suppressed.</param> /// <returns></returns> public void WalkRangeReverse(MarkupRangeWalker walker, bool inScopeContextsOnly) { MarkupPointer p1 = MarkupServices.CreateMarkupPointer(End); MarkupPointer p2 = MarkupServices.CreateMarkupPointer(End); p1.Cling = false; p2.Cling = false; MarkupContext context = new MarkupContext(); bool continueWalking = true; MarkupRange currentRange = null; while (continueWalking && p2.IsRightOf(Start)) { string text = null; bool isInScope = true; p2.Left(true, context); currentRange = new MarkupRange(p2.Clone(), p1.Clone(), MarkupServices); if (inScopeContextsOnly) { if (context.Element != null) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope) { p1.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); isInScope = InRange(p1); } else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope) { p1.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); isInScope = InRange(p1); } } else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { // It's possible part of the text is out of scope, so only return the in-scope text. if (currentRange.Start.IsLeftOf(Start)) { currentRange.Start.MoveToPointer(Start); } } } if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { text = currentRange.Text; } if (!inScopeContextsOnly || isInScope) { continueWalking = walker(currentRange, context, text); } p1.MoveToPointer(p2); } }
public void EnsureStartIsBeforeEnd() { if (Start.IsRightOf(End)) { MarkupPointer temp = End.Clone(); End = Start.Clone(); Start = temp; } }
private static void MoveUnitBounded(MarkupPointer p, MoveDirection direction, MoveContextFilter continueFilter, MarkupPointer boundary) { MarkupPointer p1 = p.Clone(); MarkupPointer lastGoodPosition = p.Clone(); MarkupContext context = new MarkupContext(); MoveFilterResult result = MoveFilterResult.CONTINUE; while (CheckMoveBoundary(p1, boundary, direction) && result == MoveFilterResult.CONTINUE) { lastGoodPosition.MoveToPointer(p1); MovePointer(p1, direction, context); result = continueFilter(context); } if (result == MoveFilterResult.CONTINUE) { //we hit the boundary, so position pointer at the boundary p1.MoveToPointer(boundary); } else if (result == MoveFilterResult.STOP_BACK) { p1.MoveToPointer(lastGoodPosition); } p.MoveToPointer(p1); }
private MarkupPointer GetFirstTextPoint(MarkupPointer from, bool forward) { MarkupPointer firstTextPoint = from.Clone(); MarkupContext context = new MarkupContext(); bool keepLooking = true; do { if (forward) { firstTextPoint.Right(false, context); } else { firstTextPoint.Left(false, context); } if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { break; } if (forward) { firstTextPoint.Right(true, context); keepLooking = context.Element != null && firstTextPoint.IsLeftOf(End); } else { firstTextPoint.Left(true, context); keepLooking = context.Element != null && firstTextPoint.IsRightOf(Start); } } while (keepLooking); return(firstTextPoint); }
private IHTMLElement GetNextElement(MarkupPointer start, MarkupRange boundaries, IHTMLElementFilter filter, bool forward) { start = start.Clone(); MarkupPointer boundary = forward ? boundaries.End : boundaries.Start; MarkupContext moveResult = new MarkupContext(); _MARKUP_CONTEXT_TYPE skipContext = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope; //advance the pointer if (forward) start.Right(true, moveResult); else start.Left(true, moveResult); while (forward ? start.IsLeftOf(boundary) : start.IsRightOf(boundary)) { if (moveResult.Element != null && moveResult.Context != skipContext && filter(moveResult.Element)) { return moveResult.Element; } //advance the pointer if (forward) start.Right(true, moveResult); else start.Left(true, moveResult); } return null; }
/// <summary> /// Returns the bounds of line that the pointer is positioned within in client-based coordinates. /// </summary> /// <param name="pointer"></param> /// <returns></returns> protected Rectangle GetLineClientRectangle(MarkupPointer pointer) { //getting the line associated with a pointer is a little complicated because the //ILineInfo for the pointer position only returns information based on the font //exactly at that position. It does not take the max font height of the line into //account, so we need to that manually. To do this, we get the LineInfo at each //point in the line where the line height may change by moving a markup pointer //in to each element declared on the line. IDisplayServicesRaw displayServices = (IDisplayServicesRaw)HTMLElement.document; //position a display pointer on the same line as the markup pointer IDisplayPointerRaw displayPointer; displayServices.CreateDisplayPointer(out displayPointer); DisplayServices.TraceMoveToMarkupPointer(displayPointer, pointer); //position a markup pointer at the end of the line MarkupPointer pLineEnd = pointer.Clone(); displayPointer.MoveUnit(_DISPLAY_MOVEUNIT.DISPLAY_MOVEUNIT_CurrentLineEnd, 0); displayPointer.PositionMarkupPointer(pLineEnd.PointerRaw); //position a markup pointer at the start of the line MarkupPointer pLineStart = pointer.Clone(); displayPointer.MoveUnit(_DISPLAY_MOVEUNIT.DISPLAY_MOVEUNIT_CurrentLineStart, 0); displayPointer.PositionMarkupPointer(pLineStart.PointerRaw); //calculate the maximum rectangle taken up by any text on this line by walking //the lineStart pointer to the lineEnd pointer and calculating a max rectangle //at each step. Rectangle lineRect = GetLineRect(HTMLElement, displayPointer); pLineStart.Right(true); while (pLineStart.IsLeftOfOrEqualTo(pLineEnd)) { Rectangle dpLineRect; try { displayPointer.MoveToMarkupPointer(pLineStart.PointerRaw, null); dpLineRect = GetLineRect(HTMLElement, displayPointer); } catch (COMException e) { if (e.ErrorCode == IE_CTL_E.INVALIDLINE) { // http://msdn.microsoft.com/en-us/library/aa752674(VS.85).aspx // IDisplayPointer::MoveToMarkupPointer will return an error (CTL_E_INVALIDLINE), // if the markup pointer is in a line whose nearest layout element *is not a flow layout element*. dpLineRect = GetLineRect(pLineStart.CurrentScope); // We also want to skip past the entire current scope... pLineStart.MoveAdjacentToElement(pLineStart.CurrentScope, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd); } else { Trace.Fail("Exception thrown in GetLineClientRectangle: " + e.ToString()); throw; } } lineRect.Y = Math.Min(dpLineRect.Y, lineRect.Y); if (lineRect.Bottom < dpLineRect.Bottom) { lineRect.Height += dpLineRect.Bottom - lineRect.Bottom; } pLineStart.Right(true); } //return the line rectangle return lineRect; }
/// <summary> /// Grabs HTML copied in the clipboard and pastes it into the document (pulls in a copy of embedded content too) /// </summary> protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { using (new WaitCursor()) { try { string baseUrl = UrlHelper.GetBasePathUrl(DataMeister.HTMLData.SourceURL); string html = DataMeister.HTMLData.HTMLSelection; //Check to see if the selection has an incomplete unordered list var finder = new IncompleteListFinder(html); finder.Parse(); if ((!EditorContext.CleanHtmlOnPaste) || finder.HasIncompleteList) { using (IUndoUnit undoUnit = EditorContext.CreateInvisibleUndoUnit()) { // Create a new MarkupContainer off of EditorContext's document that contains the source HTML // with comments marking the start and end selection. MarkupContainer sourceContainer = EditorContext.MarkupServices.ParseString(DataMeister.HTMLData.HTMLWithMarkers); // MSHTML's ParseString implementation clears all the attributes on the <body> element, so we // have to manually add them back in. CopyBodyAttributes(DataMeister.HTMLData.HTMLWithMarkers, sourceContainer.Document.body); MarkupRange sourceRange = FindMarkedFragment(sourceContainer.Document, HTMLDataObject.START_FRAGMENT_MARKER, HTMLDataObject.END_FRAGMENT_MARKER); MshtmlMarkupServices sourceContainerMarkupServices = new MshtmlMarkupServices((IMarkupServicesRaw)sourceContainer.Document); // Some applications may not add the correct fragment markers (e.g. copying from Fiddler from // the Web Sessions view). We'll just select the entire <body> of the clipboard in this case. if (sourceRange == null) { sourceRange = sourceContainerMarkupServices.CreateMarkupRange(sourceContainer.Document.body, false); } else { // Make sure that we don't try to copy just parts of a table/list. We need to include the // parent table/list. if (!EditorContext.CleanHtmlOnPaste) { ExpandToIncludeTables(sourceRange, sourceContainerMarkupServices); } ExpandToIncludeLists(sourceRange, sourceContainerMarkupServices); } if (sourceRange != null) { if (!EditorContext.CleanHtmlOnPaste) { // WinLive 273280: Alignment on a table acts like a float, which can throw off the layout of the rest of // the document. If there is nothing before or after the table, then we can safely remove the alignment. RemoveAlignmentIfSingleTable(sourceRange); // Serialize the source HTML to a string while keeping the source formatting. MarkupRange destinationRange = EditorContext.MarkupServices.CreateMarkupRange(begin.Clone(), end.Clone()); html = KeepSourceFormatting(sourceRange, destinationRange); } else { html = sourceRange.HtmlText; } } undoUnit.Commit(); } Trace.Assert(html != null, "Inline source CSS failed!"); } if (html == null) { html = DataMeister.HTMLData.HTMLSelection; } if (IsPasteFromSharedCanvas(DataMeister)) { if (action == DataAction.Copy) { // WinLive 96840 - Copying and pasting images within shared canvas should persist source // decorator settings. "wlCopySrcUrl" is inserted while copy/pasting within canvas. html = EditorContext.FixImageReferences(ImageCopyFixupHelper.FixupSourceUrlForCopy(html), DataMeister.HTMLData.SourceURL); } } else { html = EditorContext.FixImageReferences(html, DataMeister.HTMLData.SourceURL); HtmlCleanupRule cleanupRule = HtmlCleanupRule.Normal; if (IsOfficeHtml(DataMeister.HTMLData)) cleanupRule = HtmlCleanupRule.PreserveTables; // In Mail, we want to preserve the style of the html that is on the clipboard // Whereas in Writer we by default want to remove formatting so it looks like your blog theme if (EditorContext.CleanHtmlOnPaste) { // optionally cleanup the html html = EditorContext.HtmlGenerationService.CleanupHtml(html, baseUrl, cleanupRule); } else { html = HtmlCleaner.StripNamespacedTagsAndCommentsAndMarkupDirectives(html); } // standard fixups html = EditorContext.HtmlGenerationService.GenerateHtmlFromHtmlFragment(html, baseUrl); } // insert the content if (EditorContext.MarshalHtmlSupported) EditorContext.InsertHtml(begin, end, html, DataMeister.HTMLData.SourceURL); else if (EditorContext.MarshalTextSupported) { // This is called only in the case that we're attempting to marshal HTML, but only // text is supported. In this case, we should down convert to text and provide that. html = HTMLDocumentHelper.HTMLToPlainText(html); EditorContext.InsertHtml(begin, end, html, DataMeister.HTMLData.SourceURL); } else Debug.Assert(false, "Html being inserted when text or html isn't supported."); // Now select what was just inserted EditorContext.MarkupServices.CreateMarkupRange(begin, end).ToTextRange().select(); //place the caret at the end of the inserted content //EditorContext.MoveCaretToMarkupPointer(end, true); return true; } catch (Exception e) { //bugfix 1696, put exceptions into the trace log. Trace.Fail("Exception while inserting HTML: " + e.Message, e.StackTrace); return false; } } }
private MarkupPointer GetFirstTextPoint(MarkupPointer from, bool forward) { MarkupPointer firstTextPoint = from.Clone(); MarkupContext context = new MarkupContext(); bool keepLooking = true; do { if (forward) firstTextPoint.Right(false, context); else firstTextPoint.Left(false, context); if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) break; if (forward) { firstTextPoint.Right(true, context); keepLooking = context.Element != null && firstTextPoint.IsLeftOf(End); } else { firstTextPoint.Left(true, context); keepLooking = context.Element != null && firstTextPoint.IsRightOf(Start); } } while (keepLooking); return firstTextPoint; }
public static void MoveUnitBounded(MarkupPointer p, MoveDirection direction, MarkupPointerAdjacency stopRule, IHTMLElement boundary) { MarkupPointer pBoundary = p.Clone(); pBoundary.MoveAdjacentToElement(boundary, direction == MoveDirection.LEFT ? _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin : _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd); MoveUnitBounded(p, direction, stopRule, pBoundary); }