private static YogaSize MeasureText(ReactTextShadowNode textNode, YogaNode node, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode)
        {
            // TODO: Measure text with DirectWrite or other API that does not
            // require dispatcher access. Currently, we're instantiating a
            // second CoreApplicationView (that is never activated) and using
            // its Dispatcher thread to calculate layout.
            var textBlock = new RichTextBlock
            {
                TextWrapping  = TextWrapping.Wrap,
                TextAlignment = TextAlignment.DetectFromContent,
                TextTrimming  = TextTrimming.CharacterEllipsis,
            };

            textNode.UpdateTextBlockCore(textBlock, true);

            var block = new Paragraph();

            for (var i = 0; i < textNode.ChildCount; ++i)
            {
                var child = textNode.GetChildAt(i);
                block.Inlines.Add(ReactInlineShadowNodeVisitor.Apply(child));
            }
            textBlock.Blocks.Add(block);

            var normalizedWidth  = YogaConstants.IsUndefined(width) ? double.PositiveInfinity : width;
            var normalizedHeight = YogaConstants.IsUndefined(height) ? double.PositiveInfinity : height;

            textBlock.Measure(new Size(normalizedWidth, normalizedHeight));
            return(MeasureOutput.Make(
                       (float)Math.Ceiling(textBlock.DesiredSize.Width),
                       (float)Math.Ceiling(textBlock.DesiredSize.Height)));
        }
        private void AddPages(Size containerSize, RichTextBlock layout)
        {
            if (_flip.Items != null)
            {
                _flip.Items.Add(new FlipViewItem {
                    Content = layout
                });
                layout.Measure(containerSize);

                if (layout.HasOverflowContent)
                {
                    var richTextBlockOverflow = new RichTextBlockOverflow();
                    layout.OverflowContentTarget = richTextBlockOverflow;
                    _flip.Items.Add(new FlipViewItem()
                    {
                        Content = richTextBlockOverflow
                    });
                    richTextBlockOverflow.Measure(containerSize);

                    while (richTextBlockOverflow.HasOverflowContent)
                    {
                        var newRichTextBlockOverflow = new RichTextBlockOverflow();
                        richTextBlockOverflow.OverflowContentTarget = newRichTextBlockOverflow;
                        richTextBlockOverflow = newRichTextBlockOverflow;
                        _flip.Items.Add(new FlipViewItem()
                        {
                            Content = richTextBlockOverflow
                        });
                        richTextBlockOverflow.Measure(containerSize);
                    }
                }
            }
        }
        public RichTextBlock CalculateHeight(RichTextBlock currentTextBlock, double width)
        {
            var tb = new RichTextBlock {
                FontSize = currentTextBlock.FontSize
            };

            if (_text == null)
            {
                return(tb);
            }
            // Create run and set text
            Run run = new Run();

            run.Text = _text;

            // Create paragraph
            Paragraph paragraph = new Paragraph();

            // Add run to the paragraph
            paragraph.Inlines.Add(run);
            tb.Blocks.Add(paragraph);

            tb.MinWidth     = width;
            tb.MaxWidth     = width;
            tb.Width        = width;
            tb.MaxHeight    = Double.PositiveInfinity;
            tb.TextWrapping = TextWrapping.WrapWholeWords;

            tb.Measure(new Size(width, Double.PositiveInfinity));
            tb.Arrange(new Rect(0, 0, width, tb.DesiredSize.Height));
            tb.UpdateLayout();

            return(tb);
        }
        public void Changing_Inlines_Should_Reset_Inlines_Parent()
        {
            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
            {
                var target = new RichTextBlock();

                var run = new Run("Hello");

                target.Inlines.Add(run);

                target.Measure(Size.Infinity);

                Assert.True(target.IsMeasureValid);

                target.Inlines = null;

                Assert.Null(run.Parent);

                target.Inlines = new InlineCollection {
                    run
                };

                Assert.Equal(target, run.Parent);
            }
        }
        public void Changing_InlinesCollection_Should_Invalidate_Measure()
        {
            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
            {
                var target = new RichTextBlock();

                target.Measure(Size.Infinity);

                Assert.True(target.IsMeasureValid);

                target.Inlines.Add(new Run("Hello"));

                Assert.False(target.IsMeasureValid);

                target.Measure(Size.Infinity);

                Assert.True(target.IsMeasureValid);
            }
        }
        public void Changing_Inlines_Properties_Should_Invalidate_Measure()
        {
            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
            {
                var target = new RichTextBlock();

                var inline = new Run("Hello");

                target.Inlines.Add(inline);

                target.Measure(Size.Infinity);

                Assert.True(target.IsMeasureValid);

                inline.Foreground = Brushes.Green;

                Assert.False(target.IsMeasureValid);
            }
        }
        private static MeasureOutput MeasureText(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode)
        {
            // This is not a terribly efficient way of projecting the height of
            // the text elements. It requires that we have access to the
            // dispatcher in order to do measurement, which, for obvious
            // reasons, can cause perceived performance issues as it will block
            // the UI thread from handling other work.
            //
            // TODO: determine another way to measure text elements.
            var task = DispatcherHelpers.CallOnDispatcher(() =>
            {
                var textBlock = new RichTextBlock
                {
                    TextWrapping  = TextWrapping.Wrap,
                    TextAlignment = TextAlignment.DetectFromContent,
                    TextTrimming  = TextTrimming.CharacterEllipsis,
                };

                var textNode = (ReactTextShadowNode)node;
                textNode.UpdateTextBlockCore(textBlock, true);

                var block = new Paragraph();
                foreach (var child in textNode.Children)
                {
                    block.Inlines.Add(ReactInlineShadowNodeVisitor.Apply(child));
                }
                textBlock.Blocks.Add(block);

                var normalizedWidth  = CSSConstants.IsUndefined(width) ? double.PositiveInfinity : width;
                var normalizedHeight = CSSConstants.IsUndefined(height) ? double.PositiveInfinity : height;
                textBlock.Measure(new Size(normalizedWidth, normalizedHeight));
                return(new MeasureOutput(
                           (float)textBlock.DesiredSize.Width,
                           (float)textBlock.DesiredSize.Height));
            });

            return(task.Result);
        }
        async void OnFlipViewSizeChanged(object sender, SizeChangedEventArgs args)
        {
            // Get the size of the FlipView
            Size containerSize = args.NewSize;

            // Actual value gets modified during processing here, so save it
            double saveFractionRead = fractionRead;

            // First time through after program is launched
            if (flipView.Items.Count == 0)
            {
                // Load book resource
                IList <string> bookLines =
                    await PathIO.ReadLinesAsync("ms-appx:///Books/pg550.txt",
                                                UnicodeEncoding.Utf8);

                // Create RichTextBlock
                RichTextBlock richTextBlock = new RichTextBlock
                {
                    FontSize   = 22,
                    Foreground = new SolidColorBrush(Colors.Black)
                };

                // Create paragraphs
                Paragraph paragraph = new Paragraph();
                paragraph.Margin = new Thickness(12);
                richTextBlock.Blocks.Add(paragraph);

                foreach (string line in bookLines)
                {
                    // End of paragraph, make new Paragraph
                    if (line.Length == 0)
                    {
                        paragraph        = new Paragraph();
                        paragraph.Margin = new Thickness(12);
                        richTextBlock.Blocks.Add(paragraph);
                    }
                    // Continue the paragraph
                    else
                    {
                        string textLine = line;
                        char   lastChar = line[line.Length - 1];

                        if (lastChar != ' ')
                        {
                            textLine += ' ';
                        }

                        if (line[0] == ' ')
                        {
                            paragraph.Inlines.Add(new LineBreak());
                        }

                        paragraph.Inlines.Add(new Run {
                            Text = textLine
                        });
                    }
                }

                // Make RichTextBlock the same size as the FlipView
                flipView.Items.Add(richTextBlock);
                richTextBlock.Measure(containerSize);

                // Generate RichTextBlockOverflow elements
                if (richTextBlock.HasOverflowContent)
                {
                    // Add the first one
                    RichTextBlockOverflow richTextBlockOverflow = new RichTextBlockOverflow();
                    richTextBlock.OverflowContentTarget = richTextBlockOverflow;
                    flipView.Items.Add(richTextBlockOverflow);
                    richTextBlockOverflow.Measure(containerSize);

                    // Add subsequent ones
                    while (richTextBlockOverflow.HasOverflowContent)
                    {
                        RichTextBlockOverflow newRichTextBlockOverflow = new RichTextBlockOverflow();
                        richTextBlockOverflow.OverflowContentTarget = newRichTextBlockOverflow;
                        richTextBlockOverflow = newRichTextBlockOverflow;
                        flipView.Items.Add(richTextBlockOverflow);
                        richTextBlockOverflow.Measure(containerSize);
                    }
                }
            }
            // Subsequent SizeChanged events
            else
            {
                // Resize all the items in the FlipView
                foreach (object obj in flipView.Items)
                {
                    (obj as FrameworkElement).Measure(containerSize);
                }

                // Generate new RichTextBlockOverflow elements if needed
                while ((flipView.Items[flipView.Items.Count - 1]
                        as RichTextBlockOverflow).HasOverflowContent)
                {
                    RichTextBlockOverflow richTextBlockOverflow =
                        flipView.Items[flipView.Items.Count - 1] as RichTextBlockOverflow;
                    RichTextBlockOverflow newRichTextBlockOverflow = new RichTextBlockOverflow();
                    richTextBlockOverflow.OverflowContentTarget = newRichTextBlockOverflow;
                    richTextBlockOverflow = newRichTextBlockOverflow;
                    flipView.Items.Add(richTextBlockOverflow);
                    richTextBlockOverflow.Measure(args.NewSize);
                }
                // Remove superfluous RichTextBlockOverflow elements
                while (!(flipView.Items[flipView.Items.Count - 2]
                         as RichTextBlockOverflow).HasOverflowContent)
                {
                    flipView.Items.RemoveAt(flipView.Items.Count - 1);
                }
            }

            // Initialize the header and Slider
            int count = flipView.Items.Count;

            pageNumber.Text    = "1";           // probably modified soon
            pageCount.Text     = count.ToString();
            pageSlider.Minimum = 1;
            pageSlider.Maximum = flipView.Items.Count;
            pageSlider.Value   = 1;             // probably modified soon

            // Go to approximate page
            fractionRead           = saveFractionRead;
            flipView.SelectedIndex = (int)Math.Min(count - 1, fractionRead * count);
        }