Пример #1
0
        /**
         * fit the child areas into a box.
         * Essentially, each child area is given an availible space which is proportional
         * to its' strength with respect to the overall strength of the overall array. Areas
         * that can not be re-sized in the width direction (have zero width strenght) simply
         * get re-sized to thier natural width.
         *
         * NOTE: Derived classes must override this method (compound glyphs) because this returns
         * a new HorzArea, not a derived type.
         */
        public override Area Fit(BoundingBox box)
        {
            // the strength and un-adjusted size of the total array.
            Strength    s = Strength;
            BoundingBox b = BoundingBox;

            Area[] areas = new Area[content.Length];

            // new width of each child area
            float width;

            // availible space for exanding filler areas in the width direction
            // use max here, because width may be negative if we are asked to size into
            // a smaller area.
            float availibleSpace = Math.Max(0, box.Width - b.Width);

            for (int i = 0; i < content.Length; i++)
            {
                Strength    sa = content[i].Strength;
                BoundingBox ba = content[i].BoundingBox;

                if (s.Width == 0 || sa.Width == 0)
                {
                    // no re-sizing strength, so re-size to natural width
                    width = ba.Width;
                }
                else
                {
                    // re-size to natural width + % of availible space
                    width = ba.Width + availibleSpace * sa.Width / s.Width;
                }
                areas[i] = content[i].Fit(BoundingBox.New(width, box.Height, box.Depth));
            }
            return(new HorizontalArea(areas, this));
        }
Пример #2
0
        /// <summary>
        /// Get the minimum formatted area size for the given element using the
        /// state of the given formatting context.
        ///
        /// Currently this just formats the element using the this as the formatter,
        /// in the future, this will be optimized so that a visitor only calculates
        /// the min size instead of creating an entire sub tree of areas.
        /// </summary>
        public BoundingBox MeasureElement(IFormattingContext ctx, MathMLElement e)
        {
            Debug.Assert(ctx.cacheArea == false);
            if (e != null)
            {
                Area a = Area.GetArea(e);
                if (a != null)
                {
                    return(a.BoundingBox);
                }

                if (cache.Contains(e))
                {
                    return((BoundingBox)cache[e]);
                }
                else
                {
                    if (e is MathMLTableElement)
                    {
                        Debug.WriteLine("table element");
                    }
                    BoundingBox box = (BoundingBox)e.Accept(this, ctx);
                    cache.Add(e, box);
                    return(box);
                }
            }
            else
            {
                return(BoundingBox.New());
            }
        }
Пример #3
0
        /**
         * private ctor used for fit'ing
         */
        private HorizontalArea(Area[] content, Area source) : base(content, source)
        {
            // calulate bounding box
            BoundingBox box = BoundingBox.New();

            foreach (Area a in content)
            {
                box.Append(a.BoundingBox);
            }
            this.box = box;
        }
Пример #4
0
        public override AreaRegion GetEditRegion(IFormattingContext context, float x, float y, int index)
        {
            // measure horizontal position of char:
            BoundingBox horz = BoundingBox.New();
            float       left, right;

            for (int i = 0; i < index && i < content.Length; i++)
            {
                BoundingBox tmp = BoundingBox.New();
                context.MeasureGlyph(font, content[i], out tmp, out left, out right);
                horz.Append(tmp);
            }
            return(new AreaRegion(this, x + horz.Width, y));
        }
Пример #5
0
        /**
         * re-size all child nodes to the given width, and a height
         * and depth proportional
         */
        public override Area Fit(BoundingBox box)
        {
            // new content area where fitted area are written to
            Area[] newContent = new Area[content.Length];

            // bounding box (natural size), and strength of the array
            // as a whole
            BoundingBox b = BoundingBox;
            Strength    s = Strength;

            // availible height and depth distance to stretch
            float aHeight = Math.Max(0, box.Height - b.Height);
            float aDepth  = Math.Max(0, box.Depth - b.Depth);

            for (int i = 0; i < content.Length; i++)
            {
                // strength and size of the current child area
                Strength    ps = content[i].Strength;
                BoundingBox pb = content[i].BoundingBox;

                // above baseline
                if (i > baseline && s.Height > 0)
                {
                    pb.Height += (aHeight * ps.Height) / s.Height;
                    pb.Depth  += (aHeight * ps.Depth) / s.Height;
                }
                // below baseline
                else if (i < baseline && s.Depth > 0)
                {
                    pb.Height += (aDepth * ps.Height) / s.Depth;
                    pb.Depth  += (aDepth * ps.Depth) / s.Depth;
                }
                // is baseline
                else if (i == baseline && s.Height + s.Depth > 0)
                {
                    if (s.Height > 0)
                    {
                        pb.Height += (aHeight * ps.Height) / s.Height;
                    }
                    if (s.Depth > 0)
                    {
                        pb.Depth += (aDepth * ps.Depth) / s.Depth;
                    }
                }

                newContent[i] = content[i].Fit(BoundingBox.New(box.Width, pb.Height, pb.Depth));
            }
            return(new VerticalArea(newContent, baseline, this));
        }
Пример #6
0
 public BoundingBox[] MeasureElements(IFormattingContext ctx, MathMLElement[] elements)
 {
     BoundingBox[] boxes = new BoundingBox[elements.Length];
     for (int i = 0; i < elements.Length; i++)
     {
         if (elements[i] != null)
         {
             boxes[i] = MeasureElement(ctx, elements[i]);
         }
         else
         {
             boxes[i] = BoundingBox.New();
         }
     }
     return(boxes);
 }
Пример #7
0
        /**
         * create a string area
         */
        public StringArea(IFormattingContext context, string content)
        {
            this.font    = context.GetFont();
            this.content = content;
            box          = BoundingBox.New();

            float left = 0, right = 0;

            for (int i = 0; i < content.Length; i++)
            {
                BoundingBox tmp = BoundingBox.New();
                context.MeasureGlyph(font, content[i], out tmp, out left, out right);
                box.Append(tmp);

                // left edge of first char
                if (i == 0)
                {
                    leftEdge = left;
                }
            }

            // right edge of last char
            rightEdge = right;
        }
Пример #8
0
        object MathML.MathMLVisitor.Visit(MathMLPresentationContainer e, object args)
        {
            IFormattingContext context   = ((IFormattingContext)args).Clone();
            MathMLNodeList     arguments = e.Arguments;
            BoundingBox        extent    = BoundingBox.New();
            int stretchCount             = 0;

            // save the stretch size because stretch scope can not extend into another
            // level of nesting
            BoundingBox stretch = context.Stretch;

            context.Stretch = BoundingBox.New();

            // process all nodes that are not stretchy operators, get thier total
            // extents
            for (int i = 0; i < arguments.Count; i++)
            {
                MathMLElement         element = (MathMLElement)arguments[i];
                MathMLOperatorElement op      = element as MathMLOperatorElement;

                if (op == null || op.Stretchy == false)
                {
                    //areas[i] = (Area)element.Accept(this, context);
                    extent.Append((BoundingBox)element.Accept(this, context));
                }
                if (op != null && op.Stretchy)
                {
                    stretchCount++;
                }
            }

            // if we have any elements that can be stretched, stretch them
            if (stretchCount > 0)
            {
                if (!stretch.Defined)
                {
                    // avail width is epsilon because stretchy glyphs were not counted in the
                    // width calculation
                    context.Stretch = BoundingBox.New(Single.Epsilon, extent.Height, extent.Depth);
                }
                else
                {
                    // set the stretch size back to stretch the child elements
                    context.Stretch = stretch;

                    // calculate availible width
                    context.StretchWidth = context.StretchWidth - extent.Width;
                    if (context.Stretch.Width < 0)
                    {
                        context.StretchWidth = 0;
                    }

                    // size to stretch each width equally
                    context.StretchWidth = context.Stretch.Width / (float)stretchCount;
                }

                // process all areas that need to be stretched
                for (int i = 0; i < arguments.Count; i++)
                {
                    MathMLOperatorElement op = arguments[i] as MathMLOperatorElement;
                    if (op != null && op.Stretchy)
                    {
                        //areas[i] = (Area)op.Accept(this, context);
                        extent.Append((BoundingBox)op.Accept(this, context));
                    }
                }
            }

            return(extent);
        }
Пример #9
0
        /**
         * format a script area. This is an area with a base, and
         * optional super and subscript areas.
         */
        public static Area Script(IFormattingContext context, Area baseArea,
                                  Area subArea, Length subMinShift, Area superArea, Length superMinShift)
        {
            // we might have a italic base where we have an overhang at the top, in this
            // case we need to add a space for the script elements
            float right = baseArea.RightEdge;

            // index where to put script elements
            int scriptIndex;

            // horz area, length = 2, base + scripts or length = 3: base + space + scripts
            Area[] horz;
            float  subShift, superShift;

            if (right < 0)
            {
                scriptIndex = 2;
                horz        = new Area[3];
                horz[1]     = new HorizontalSpaceArea(-right);
            }
            else
            {
                scriptIndex = 1;
                horz        = new Area[2];
            }

            // set the base
            horz[0] = baseArea;

            CalculateScriptShift(context,
                                 baseArea.BoundingBox,
                                 subArea != null ? subArea.BoundingBox : BoundingBox.New(),
                                 subMinShift,
                                 superArea != null ? superArea.BoundingBox : BoundingBox.New(),
                                 superMinShift,
                                 out subShift, out superShift);

            // the script areas go in an overlap area
            if (subArea != null && superArea != null)
            {
                Area[] overlap = new Area[2];
                overlap[0]        = Shift(-subShift, subArea);
                overlap[1]        = Shift(superShift, superArea);
                horz[scriptIndex] = Overlap(overlap);
            }
            else if (subArea != null)
            {
                horz[scriptIndex] = Shift(-subShift, subArea);
            }
            else if (superArea != null)
            {
                horz[scriptIndex] = Shift(superShift, superArea);
            }
            else
            {
                // no script areas, this is not good, but deal with it anyway
                Debug.WriteLine("Warning, no script areas while create a script area, creating default glyph area");
                horz[scriptIndex] = String(context, "?");
            }

            // make a horizontal area out of these
            return(Horizontal(horz));
        }
Пример #10
0
        /**
         * construct a new sizer. All calculations are done here.
         */
        public MathMLTableSizer(IFormattingContext ctx, MathMLMeasurer measurer, MathMLTableElement table)
        {
            try
            {
                // copy the context because we change the stretch size so not to
                // stretch tables
                ctx           = ctx.Clone();
                ctx.Stretch   = BoundingBox.New();
                ctx.cacheArea = false;

                //MathMLMeasurer measurer = new MathMLMeasurer();
                equalColumns = table.EqualColumns;

                // get the cells from the table and store them in a multi dim array
                cells = GetCells(table);

                // min area sizes for the cells

                BoundingBox[][] minCellSizes = measurer.MeasureElements(ctx, cells);
                DebugWriteCellSizes(minCellSizes);

                // count of columns that are actual table cells
                int cellColumnCount = GetCellColumnCount(cells);

                // column widths attr from dom
                Length[] columnWidths = GetColumnWidths(table, cellColumnCount);

                // column space attr from dom
                Length[] columnSpacing = GetColumnSpacing(table, cellColumnCount - 1);

                // frame spaceing attr from dom
                Length[] frameSpacing = table.FrameSpacing;

                // row spacing attr from dom
                Length[] rowSpacing = GetRowSpacing(table, cells.Length - 1);

                // create a set of columns from the cells
                columns = CreateColumns(ctx, measurer, cells, minCellSizes, cellColumnCount, columnWidths,
                                        columnSpacing, frameSpacing[0]);

                // create a set of row measurments, this is both the cell rows and spacing rows
                Row[] rows = CreateRows(ctx, cells, minCellSizes, rowSpacing, frameSpacing[1]);

                // adjust rows and columns so there is enough space to fit spanning cells
                AdjustSpanningCells(cells, minCellSizes, rows, columns);

                Debug.WriteLine("retrieved " + columns.Length + "total columns, ");
                DebugWriteColumnWidths("Initial Column Widths: ");

                // get the minimum area for the columns
                float tableWidth = CalculateTableWidth(ctx, table, columns, equalColumns, cellColumnCount);
                Debug.WriteLine("Minimum Table Width: " + tableWidth);

                // find the space needed to fit the availible for the auto and fit columns
                float availSpace = CalculateColumnAvailSpace(columns, tableWidth);
                Debug.WriteLine("Availible Space For Columns: " + availSpace);

                // set the table widths
                DistributeSpace(columns, tableWidth, availSpace, cellColumnCount, equalColumns);

                DebugWriteColumnWidths("Column Widths After Formatting: ");

                // calcuate the shift
                float shift = 0;
                CalculateShiftAndSize(ctx, table, rows, columns, ref box, ref shift);

                // create the cell sizes and offsets
                CreateCellSizesAndShifts(cells, rows, columns, ref cellSizes, ref cellShifts);


                // create the lines for the frame and cell separators
                LineStyle   frame       = table.Frame;
                LineStyle[] columnLines = GetColumnLines(table, cellColumnCount);
                LineStyle[] rowLines    = GetRowLines(table, cells.Length);
                CreateLines(cellSizes, cells, rows, columns, columnLines, rowLines, frame);

                // set the shift
                tableShift = GetTableShift(ctx, table, box);
            }
            catch (Exception ex)
            {
                throw new Exception("Error constructing table sizer: " + ex.Message);
            }
        }