/// <summary>
        /// Renders the buffer to the specified target graphics.
        /// </summary>
        public void Render(Graphics?target)
        {
            if (target != null)
            {
                IntPtr targetDC = target.GetHdc();

                try
                {
                    RenderInternal(new HandleRef(target, targetDC));
                }
                finally
                {
                    target.ReleaseHdcInternal(targetDC);
                }
            }
        }
        public bool IsOutlineVisible(Point pt, Pen pen, Graphics?graphics)
        {
            if (pen == null)
            {
                throw new ArgumentNullException(nameof(pen));
            }

            Gdip.CheckStatus(Gdip.GdipIsOutlineVisiblePathPointI(
                                 new HandleRef(this, _nativePath),
                                 pt.X, pt.Y,
                                 new HandleRef(pen, pen.NativePen),
                                 new HandleRef(graphics, graphics?.NativeGraphics ?? IntPtr.Zero),
                                 out bool isVisible));

            return(isVisible);
        }
예제 #3
0
        public bool IsOutlineVisible(float x, float y, Pen pen, Graphics?graphics)
        {
            if (pen == null)
            {
                throw new ArgumentNullException(nameof(pen));
            }

            bool   result;
            IntPtr g = (graphics == null) ? IntPtr.Zero : graphics.NativeGraphics;

            int s = Gdip.GdipIsOutlineVisiblePathPoint(_nativePath, x, y, pen.NativePen, g, out result);

            Gdip.CheckStatus(s);

            return(result);
        }
        public void Dispose()
        {
            if (membmp != null)
            {
                membmp.Dispose();
                membmp = null !;
            }

            if (source != null)
            {
                source.Dispose();
                source = null;
            }

            _targetGraphics = null;
        }
예제 #5
0
        private const int BufferBusyDisposing = 2; // The graphics buffer is busy disposing.

        /// <summary>
        /// Returns a BufferedGraphics that is matched for the specified target HDC object.
        /// </summary>
        private BufferedGraphics AllocBuffer(Graphics?targetGraphics, IntPtr targetDC, Rectangle targetRectangle)
        {
            int oldBusy = Interlocked.CompareExchange(ref _busy, BufferBusyPainting, BufferFree);

            // In the case were we have contention on the buffer - i.e. two threads
            // trying to use the buffer at the same time, we just create a temp
            // buffermanager and have the buffer dispose of it when it is done.
            //
            if (oldBusy != BufferFree)
            {
                return(AllocBufferInTempManager(targetGraphics, targetDC, targetRectangle));
            }

            Graphics surface;

            _targetLoc = new Point(targetRectangle.X, targetRectangle.Y);

            try
            {
                if (targetGraphics != null)
                {
                    IntPtr destDc = targetGraphics.GetHdc();
                    try
                    {
                        surface = CreateBuffer(destDc, -_targetLoc.X, -_targetLoc.Y, targetRectangle.Width, targetRectangle.Height);
                    }
                    finally
                    {
                        targetGraphics.ReleaseHdcInternal(destDc);
                    }
                }
                else
                {
                    surface = CreateBuffer(targetDC, -_targetLoc.X, -_targetLoc.Y, targetRectangle.Width, targetRectangle.Height);
                }

                _buffer = new BufferedGraphics(surface, this, targetGraphics, targetDC, _targetLoc, _virtualSize);
            }
            catch
            {
                // Free the buffer so it can be disposed.
                _busy = BufferFree;
                throw;
            }

            return(_buffer);
        }
예제 #6
0
        /// <summary>
        /// Implements StartPage for printing to a physical printer.
        /// </summary>
        public override Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)
        {
            Debug.Assert(_dc != null && _graphics == null, "PrintController methods called in the wrong order?");
            Debug.Assert(_modeHandle != null);

            base.OnStartPage(document, e);
            e.PageSettings.CopyToHdevmode(_modeHandle);
            IntPtr modePointer = Interop.Kernel32.GlobalLock(new HandleRef(this, _modeHandle));

            try
            {
                IntPtr result = Interop.Gdi32.ResetDC(new HandleRef(_dc, _dc.Hdc), new HandleRef(null, modePointer));
                Debug.Assert(result == _dc.Hdc, "ResetDC didn't return the same handle I gave it");
            }
            finally
            {
                Interop.Kernel32.GlobalUnlock(new HandleRef(this, _modeHandle));
            }

            _graphics = Graphics.FromHdcInternal(_dc.Hdc);

            if (document.OriginAtMargins)
            {
                // Adjust the origin of the graphics object to be at the
                // user-specified margin location
                //
                int   dpiX           = Interop.Gdi32.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), Interop.Gdi32.DeviceCapability.LOGPIXELSX);
                int   dpiY           = Interop.Gdi32.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), Interop.Gdi32.DeviceCapability.LOGPIXELSY);
                int   hardMarginX_DU = Interop.Gdi32.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), Interop.Gdi32.DeviceCapability.PHYSICALOFFSETX);
                int   hardMarginY_DU = Interop.Gdi32.GetDeviceCaps(new HandleRef(_dc, _dc.Hdc), Interop.Gdi32.DeviceCapability.PHYSICALOFFSETY);
                float hardMarginX    = hardMarginX_DU * 100 / dpiX;
                float hardMarginY    = hardMarginY_DU * 100 / dpiY;

                _graphics.TranslateTransform(-hardMarginX, -hardMarginY);
                _graphics.TranslateTransform(document.DefaultPageSettings.Margins.Left, document.DefaultPageSettings.Margins.Top);
            }


            int result2 = Interop.Gdi32.StartPage(new HandleRef(_dc, _dc.Hdc));

            if (result2 <= 0)
            {
                throw new Win32Exception();
            }
            return(_graphics);
        }
예제 #7
0
        /// <summary>
        ///  If ControlStyles.AllPaintingInWmPaint, we call this method after OnPaintBackground so it appears to
        ///  OnPaint that it's getting a fresh Graphics.  We want to make sure AllPaintingInWmPaint is purely an
        ///  optimization, and doesn't change behavior, so we need to make sure any clipping regions established in
        ///  OnPaintBackground don't apply to OnPaint.
        /// </summary>
        internal void ResetGraphics()
        {
            Graphics?graphics = _event.GetGraphics(create: false);

            if (_event.Flags.HasFlag(DrawingEventFlags.SaveState) && graphics is not null)
            {
                if (_savedGraphicsState is not null)
                {
                    graphics.Restore(_savedGraphicsState);
                    _savedGraphicsState = null;
                }
                else
                {
                    Debug.Fail("Called ResetGraphics more than once?");
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Get a fresh clear bitmap buffer ready for drawing on
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        private Graphics GetBitmapBuffer(int width, int height)
        {
            // Create a new one if we haven't got one, or the size has changed
            if (_gameGraphics == null || _gameBuffer == null || _gameBuffer.Height != height || _gameBuffer.Width != width)
            {
                _gameGraphics?.Dispose();
                _gameBuffer?.Dispose();

                _gameBuffer   = new Bitmap(width, height);
                _gameGraphics = Graphics.FromImage(_gameBuffer);

                _gameGraphics.SmoothingMode     = SmoothingMode.None;
                _gameGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            }

            return(_gameGraphics);
        }
        /// <summary>
        ///  Prefer to use <see cref="DeviceContextHdcScope(IDeviceContext, bool, bool)"/>.
        /// </summary>
        /// <remarks>
        ///  <para>
        ///   Ideally we'd not bifurcate what properties we apply unless we're absolutely sure we only want one.
        ///  </para>
        /// </remarks>
        public unsafe DeviceContextHdcScope(
            IDeviceContext deviceContext,
            ApplyGraphicsProperties applyGraphicsState,
            bool saveHdcState = false)
        {
            if (deviceContext is null)
            {
                // As we're throwing in the constructor, `this` will never be passed back and as such .Dispose()
                // can't be called. We don't have anything to release at this point so there is no point in having
                // the finalizer run.
#if DEBUG
                DisposalTracking.SuppressFinalize(this !);
#endif
                throw new ArgumentNullException(nameof(deviceContext));
            }

            DeviceContext  = deviceContext;
            _savedHdcState = 0;

            HDC = default;

            IGraphicsHdcProvider?provider = deviceContext as IGraphicsHdcProvider;
            Graphics?            graphics = deviceContext as Graphics;

            // There are three states of IDeviceContext that come into this class:
            //
            //  1. One that also implements IGraphicsHdcProvider
            //  2. One that is directly on Graphics
            //  3. All other IDeviceContext instances
            //
            // In the third case there is no Graphics to apply Properties from. In the second case we must query
            // the Graphics object itself for Properties (transform and clip). In the first case the
            // IGraphicsHdcProvider will let us know if we have an "unclean" Graphics object that we need to apply
            // Properties from.
            //
            // PaintEventArgs implements IGraphicsHdcProvider and uses it to let us know that either (1) a Graphics
            // object hasn't been created yet, OR (2) the Graphics object has never been given a transform or clip.

            bool needToApplyProperties = applyGraphicsState != ApplyGraphicsProperties.None;
            if (graphics is null && provider is null)
            {
                // We have an IDeviceContext (case 3 above), we can't apply properties because there is no
                // Graphics object available.
                needToApplyProperties = false;
            }
예제 #10
0
        internal static void CheckGraphicsForState(Graphics?graphics, DrawingEventFlags flags)
        {
            if (graphics is null || !flags.HasFlag(DrawingEventFlags.CheckState) ||
                flags.HasFlag(DrawingEventFlags.GraphicsStateUnclean))
            {
                return;
            }

            // Check to see if we've actually corrupted the state
            graphics.GetContextInfo(out PointF offset, out Region? clip);

            using (clip)
            {
                bool isInfinite = clip?.IsInfinite(graphics) ?? true;
                Debug.Assert(offset.IsEmpty, "transform has been modified");
                Debug.Assert(isInfinite, "clipping as been applied");
            }
        }
        /// <summary>
        ///  Implements StartPage by delegating to the underlying controller.
        /// </summary>
        public override Graphics?OnStartPage(PrintDocument document, PrintPageEventArgs e)
        {
            base.OnStartPage(document, e);

            if (_backgroundThread is not null)
            {
                _backgroundThread.UpdateLabel();
            }

            Graphics?result = _underlyingController.OnStartPage(document, e);

            if (_backgroundThread is not null && _backgroundThread._canceled)
            {
                e.Cancel = true;
            }

            return(result);
        }
예제 #12
0
        private void CustomPaint()
        {
            if (IsImeStartingComposition)
            {
                return;
            }

            if (_bitmap is null || (_bitmap.Width != _richTextBox.Width || _bitmap.Height != _richTextBox.Height))
            {
                _bitmap              = new Bitmap(_richTextBox.Width, _richTextBox.Height, PixelFormat.Format32bppPArgb);
                _bufferGraphics      = Graphics.FromImage(_bitmap);
                _bufferGraphics.Clip = new Region(_richTextBox.ClientRectangle);
                _textBoxGraphics     = Graphics.FromHwnd(_richTextBox.Handle);
            }

            // clear the graphics buffer
            _bufferGraphics !.Clear(Color.Transparent);

            // * Here’s where the magic happens

            // Mark ill formed parts of commit message
            DrawLines(IllFormedLines, DrawType.Mark);

            // Mark first line if it is blank
            var lh   = LineHeight();
            var ypos = _richTextBox.GetPositionFromCharIndex(0).Y;

            if (_richTextBox.Text.Length > 1 &&

                // check for textBox.Text.Length>1 instead of textBox.Text.Length!=0 because there might be only a \n
                _richTextBox.Lines.Length > 0 && _richTextBox.Lines[0].Length == 0 &&
                ypos >= -lh && AppSettings.MarkIllFormedLinesInCommitMsg)
            {
                DrawMark(new Point(0, lh + ypos), new Point(_richTextBox.Width - 3, lh + ypos));
            }

            // Mark misspelled words
            DrawLines(Lines, DrawType.Wave);

            // Now we just draw our internal buffer on top of the TextBox.
            // Everything should be at the right place.
            _textBoxGraphics !.DrawImageUnscaled(_bitmap, 0, 0);
        }
예제 #13
0
        /// <summary>
        /// Implements EndPage for printing to a physical printer.
        /// </summary>
        public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)
        {
            Debug.Assert(_dc != null && _graphics != null, "PrintController methods called in the wrong order?");

            try
            {
                int result = Interop.Gdi32.EndPage(new HandleRef(_dc, _dc.Hdc));
                if (result <= 0)
                {
                    throw new Win32Exception();
                }
            }
            finally
            {
                _graphics.Dispose(); // Dispose of GDI+ Graphics; keep the DC
                _graphics = null;
            }
            base.OnEndPage(document, e);
        }
예제 #14
0
        internal static void CheckGraphicsForState(Graphics?graphics, DrawingEventFlags flags)
        {
            if (graphics is null || !flags.HasFlag(DrawingEventFlags.CheckState) ||
                flags.HasFlag(DrawingEventFlags.GraphicsStateUnclean))
            {
                return;
            }

            // Check to see if we've actually corrupted the state
            object[] data = (object[])graphics.GetContextInfo();

            using Region clipRegion     = (Region)data[0];
            using Matrix worldTransform = (Matrix)data[1];

            float[] elements   = worldTransform?.Elements !;
            bool    isInfinite = clipRegion.IsInfinite(graphics);

            Debug.Assert((int)elements[4] == 0 && (int)elements[5] == 0, "transform has been modified");
            Debug.Assert(isInfinite, "clipping as been applied");
        }
예제 #15
0
        /// <summary>
        /// Get a fresh clear bitmap buffer ready for drawing on
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public Graphics GetBitmapBuffer(int width, int height)
        {
            // Create a new one if we haven't got one, or the size has changed
            if (_gameGraphics == null || _gameBuffer == null || _gameBuffer.Height != height || _gameBuffer.Width != width)
            {
                _gameGraphics?.Dispose();
                _gameBuffer?.Dispose();

                _gameBuffer   = new Bitmap(width, height);
                _gameGraphics = Graphics.FromImage(_gameBuffer);

                _gameGraphics.SmoothingMode     = SmoothingMode.None;
                _gameGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            }

            // Clear it and reset origin
            _gameGraphics.TranslateTransform(0, 0);
            _gameGraphics.Clear(Color.Black);

            return(_gameGraphics);
        }
예제 #16
0
        /// <summary>
        ///  Internal version of constructor for performance. We try to avoid getting the graphics object until needed.
        /// </summary>
        public DrawingEventArgs(
            Gdi32.HDC dc,
            Rectangle clipRect,
            DrawingEventFlags flags)
        {
            ArgumentValidation.ThrowIfNull(dc);

#if DEBUG
            Gdi32.OBJ type = Gdi32.GetObjectType(dc);
            Debug.Assert(type == Gdi32.OBJ.DC ||
                         type == Gdi32.OBJ.ENHMETADC ||
                         type == Gdi32.OBJ.MEMDC ||
                         type == Gdi32.OBJ.METADC);
#endif

            _hdc          = dc;
            _graphics     = null;
            _oldPalette   = default;
            Flags         = flags;
            ClipRectangle = clipRect;
        }
예제 #17
0
        /// <summary>
        ///  For internal use to improve performance. DO NOT use this method if you modify the Graphics Clip or Transform.
        /// </summary>
        internal Graphics GetOrCreateGraphicsInternal(Action <Graphics>?creationAction = null)
        {
            if (_graphics == null)
            {
                Debug.Assert(!_hdc.IsNull);

                // We need to manually unset the palette here so this scope shouldn't be disposed
                var palleteScope = Gdi32.SelectPaletteScope.HalftonePalette(
                    _hdc,
                    forceBackground: false,
                    realizePalette: false);

                _oldPalette = palleteScope.HPalette;

                _graphics          = Graphics.FromHdcInternal((IntPtr)_hdc);
                _graphics.PageUnit = GraphicsUnit.Pixel;
                creationAction?.Invoke(_graphics);

                CheckGraphicsForState(_graphics, Flags);
            }

            return(_graphics);
        }
예제 #18
0
        /// <summary>
        ///  Method to draw visualstyle themes in case of per-monitor scenarios where Hwnd is necessary
        /// </summary>
        /// <param name="hwnd"> handle to the control</param>
        internal static void DrawButtonForHandle(
            IDeviceContext deviceContext,
            Rectangle bounds,
            bool focused,
            PushButtonState state,
            IntPtr hwnd)
        {
            Rectangle contentBounds;

            if (RenderWithVisualStyles)
            {
                InitializeRenderer((int)state);

                using var hdc = new DeviceContextHdcScope(deviceContext);
                t_visualStyleRenderer.DrawBackground(hdc, bounds, hwnd);
                contentBounds = t_visualStyleRenderer.GetBackgroundContentRectangle(hdc, bounds);
            }
            else
            {
                Graphics?graphics = deviceContext.TryGetGraphics(create: true);
                if (graphics is not null)
                {
                    ControlPaint.DrawButton(graphics, bounds, ConvertToButtonState(state));
                }

                contentBounds = Rectangle.Inflate(bounds, -3, -3);
            }

            if (focused)
            {
                Graphics?graphics = deviceContext.TryGetGraphics(create: true);
                if (graphics is not null)
                {
                    ControlPaint.DrawFocusRectangle(graphics, contentBounds);
                }
            }
        }
예제 #19
0
        /// <summary>
        ///  Internal version of constructor for performance. We try to avoid getting the graphics object until needed.
        /// </summary>
        public DrawingEventArgs(
            Gdi32.HDC dc,
            Rectangle clipRect,
            DrawingEventFlags flags)
        {
            if (dc.IsNull)
            {
                throw new ArgumentNullException(nameof(dc));
            }

#if DEBUG
            Gdi32.OBJ type = Gdi32.GetObjectType(dc);
            Debug.Assert(type == Gdi32.OBJ.DC ||
                         type == Gdi32.OBJ.ENHMETADC ||
                         type == Gdi32.OBJ.MEMDC ||
                         type == Gdi32.OBJ.METADC);
#endif

            _hdc          = dc;
            _graphics     = null;
            _oldPalette   = default;
            Flags         = flags;
            ClipRectangle = clipRect;
        }
예제 #20
0
        /// <summary>
        /// Returns true if print was aborted.
        /// </summary>
        /// <remarks>
        /// If you have nested PrintControllers, this method won't get called on the inner one
        /// Add initialization code to StartPrint or StartPage instead.
        /// </remarks>
        private bool PrintLoop(PrintDocument document)
        {
            QueryPageSettingsEventArgs queryEvent = new QueryPageSettingsEventArgs((PageSettings)document.DefaultPageSettings.Clone());

            while (true)
            {
                document.OnQueryPageSettings(queryEvent);
                if (queryEvent.Cancel)
                {
                    return(true);
                }

                PrintPageEventArgs pageEvent = CreatePrintPageEvent(queryEvent.PageSettings);
                Graphics?          graphics  = OnStartPage(document, pageEvent);
                pageEvent.SetGraphics(graphics);

                try
                {
                    document.OnPrintPage(pageEvent);
                    OnEndPage(document, pageEvent);
                }
                finally
                {
                    pageEvent.Dispose();
                }

                if (pageEvent.Cancel)
                {
                    return(true);
                }
                else if (!pageEvent.HasMorePages)
                {
                    return(false);
                }
            }
        }
예제 #21
0
        internal void Dispose(bool disposing)
        {
            if (DeviceContext != null)
            {
                DbgUtil.AssertFinalization(this, disposing);

                try
                {
                    // Restore original dc.
                    DeviceContext.RestoreHdc();

                    if (_disposeDc)
                    {
                        DeviceContext.Dispose(disposing);
                    }

                    if (_graphics != null)    // if created from a Graphics object...
                    {
                        _graphics.ReleaseHdcInternal(DeviceContext.Hdc);
                        _graphics = null;
                    }
                }
                catch (Exception ex)
                {
                    if (ClientUtils.IsSecurityOrCriticalException(ex))
                    {
                        throw; // rethrow the original exception.
                    }
                    Debug.Fail("Exception thrown during disposing: \r\n" + ex.ToString());
                }
                finally
                {
                    DeviceContext = null !;
                }
            }
        }
예제 #22
0
 public bool IsVisible(int x, int y, Graphics?graphics) => IsVisible(new Point(x, y), graphics);
예제 #23
0
 public bool IsOutlineVisible(float x, float y, Pen pen, Graphics?graphics)
 {
     return(IsOutlineVisible(new PointF(x, y), pen, graphics));
 }
예제 #24
0
 public bool IsVisible(float x, float y, Graphics?graphics) => IsVisible(new PointF(x, y), graphics);
예제 #25
0
 public bool IsOutlineVisible(int x, int y, Pen pen, Graphics?graphics) => IsOutlineVisible(new Point(x, y), pen, graphics);
예제 #26
0
        // Calculate text metrics information.
        //
        // Note that this is currently broken. Turn this on at your own risk.
        public SizeF GetBounds
            (Graphics graphics, string text, Font font,
            SizeF layoutSize, StringFormat?format,
            out int charactersFitted, out int linesFilled)
        {
            // set the current graphics
            _graphics = graphics;

            // set the current text
            _text = text;

            // set the current font
            _font = font;

            // ensure we have a string format
            format ??= _defaultStringFormat;

            // set the current string format
            _format = format;

            // set the current layout rectangle
            layout = new Rectangle
                         (0, 0, (int)layoutSize.Width, (int)layoutSize.Height);

            // set the current line height
            lineHeight = font.Height;

            // set the only whole lines flag
            onlyWholeLines = (format.FormatFlags & StringFormatFlags.LineLimit) != 0 ||
                             format.Trimming == StringTrimming.None;

            nextIndex        = 0;
            lineSpaceUsedUp  = 0;
            maxLineSpaceUsed = 0;

            // set the previous span ended in new line flag
            prevIsNewLine = false;

            // select the current font into the graphics context
            graphics.SelectFont(font);

            // set the text width
            int textWidth = 0;

            // set the maximum width
            float maxWidth = 0;

            // set the default characters fitted
            charactersFitted = 0;

            // set the default lines filled
            linesFilled = 0;

            // remove the hotkey prefix, if needed
            if (format.HotkeyPrefix != HotkeyPrefix.None)
            {
                // get the hotkey index
                hotkeyIndex = text.IndexOf('&');

                // handle the hotkey as needed
                if (hotkeyIndex != -1)
                {
                    if (hotkeyIndex < (text.Length - 1) &&
                        !char.IsControl(text[hotkeyIndex + 1]))
                    {
                        // remove the hotkey character
                        text = text.Substring(0, hotkeyIndex) +
                               text.Substring(hotkeyIndex + 1);

                        // set the current text
                        _text = text;

                        // update characters fitted
                        ++charactersFitted;
                    }

                    // no need for this anymore
                    hotkeyIndex = -1;
                }
            }

            // create character spans
            CharSpan span = new();
            CharSpan prev = new();

            // set the first span flag
            bool firstSpan = true;

            // set the measure trailing spaces flag
            bool mts = ((format.FormatFlags &
                         StringFormatFlags.MeasureTrailingSpaces) != 0);

            // process the text
            while (nextIndex < text.Length)
            {
                // get the next span of characters
                GetNextSpan(span);

                // handle span on new line
                if (span.newline)
                {
                    // remove trailing spaces, if needed
                    if (!firstSpan && !mts && text[prev.start] == ' ')
                    {
                        // update the text width
                        textWidth -= GetSpanWidth(prev);
                    }

                    // update the maximum width, if needed
                    if (textWidth > maxWidth)
                    {
                        maxWidth = textWidth;
                    }

                    // update the text width
                    textWidth = 0;

                    // update the lines filled
                    ++linesFilled;
                }

                // update the text width
                textWidth += GetSpanWidth(span);

                // update the characters fitted
                charactersFitted += span.length;

                // copy span values to previous span
                span.CopyTo(prev);
            }

            // update the maximum width, if needed
            if (textWidth > maxWidth)
            {
                maxWidth = textWidth;
            }

            // update the lines filled to account for the first line
            ++linesFilled;

            // update the maximum width, if needed
            if (maxWidth > layout.Width)
            {
                maxWidth = layout.Width;
            }

            // calculate the height
            float height = (lineHeight * linesFilled);

            // update the height, if needed
            if (height > layout.Height)
            {
                height = layout.Height;
            }

            // return the size of the text
            return(new SizeF(maxWidth, height));
        }
예제 #27
0
        // methods
        public void Print()
        {
            PrintEventArgs printArgs = new PrintEventArgs();

            this.OnBeginPrint(printArgs);
            if (printArgs.Cancel)
            {
                return;
            }
            PrintController.OnStartPrint(this, printArgs);
            if (printArgs.Cancel)
            {
                return;
            }

            Graphics?g = null;

            if (printArgs.GraphicsContext != null)
            {
                g = Graphics.FromHdc(printArgs.GraphicsContext.Hdc);
                printArgs.GraphicsContext.Graphics = g;
            }

            // while there are more pages
            PrintPageEventArgs printPageArgs;

            do
            {
                QueryPageSettingsEventArgs queryPageSettingsArgs = new QueryPageSettingsEventArgs(
                    (DefaultPageSettings.Clone() as PageSettings) !);
                OnQueryPageSettings(queryPageSettingsArgs);

                PageSettings pageSettings = queryPageSettingsArgs.PageSettings;
                printPageArgs = new PrintPageEventArgs(
                    g,
                    pageSettings.Bounds,
                    new Rectangle(0, 0, pageSettings.PaperSize.Width, pageSettings.PaperSize.Height),
                    pageSettings);

                // TODO: We should create a graphics context for each page since they can have diferent paper
                // size, orientation, etc. We use a single graphic for now to keep Cairo using a single PDF file.

                printPageArgs.GraphicsContext = printArgs.GraphicsContext;
                Graphics?pg = PrintController.OnStartPage(this, printPageArgs);

                // assign Graphics in printPageArgs
                printPageArgs.SetGraphics(pg);

                if (!printPageArgs.Cancel)
                {
                    this.OnPrintPage(printPageArgs);
                }

                PrintController.OnEndPage(this, printPageArgs);
                if (printPageArgs.Cancel)
                {
                    break;
                }
            } while (printPageArgs.HasMorePages);

            this.OnEndPrint(printArgs);
            PrintController.OnEndPrint(this, printArgs);
        }
예제 #28
0
        private bool PrintLoopOptimized(PrintDocument document)
        {
            PrintPageEventArgs?        pageEvent            = null;
            PageSettings               documentPageSettings = (PageSettings)document.DefaultPageSettings.Clone();
            QueryPageSettingsEventArgs queryEvent           = new QueryPageSettingsEventArgs(documentPageSettings);

            while (true)
            {
                queryEvent.PageSettingsChanged = false;
                document.OnQueryPageSettings(queryEvent);
                if (queryEvent.Cancel)
                {
                    return(true);
                }

                if (!queryEvent.PageSettingsChanged)
                {
                    // QueryPageSettings event handler did not change the page settings,
                    // thus we use default page settings from the document object.
                    if (pageEvent == null)
                    {
                        pageEvent = CreatePrintPageEvent(queryEvent.PageSettings);
                    }
                    else
                    {
                        // This is not the first page and the settings had not changed since the previous page,
                        // thus don't re-apply them.
                        pageEvent.CopySettingsToDevMode = false;
                    }

                    Graphics?graphics = OnStartPage(document, pageEvent);
                    pageEvent.SetGraphics(graphics);
                }
                else
                {
                    // Page settings were customized, so use the customized ones in the start page event.
                    pageEvent = CreatePrintPageEvent(queryEvent.PageSettings);
                    Graphics?graphics = OnStartPage(document, pageEvent);
                    pageEvent.SetGraphics(graphics);
                }

                try
                {
                    document.OnPrintPage(pageEvent);
                    OnEndPage(document, pageEvent);
                }
                finally
                {
                    pageEvent.Graphics !.Dispose();
                    pageEvent.SetGraphics(null);
                }

                if (pageEvent.Cancel)
                {
                    return(true);
                }
                else if (!pageEvent.HasMorePages)
                {
                    return(false);
                }
            }
        }
예제 #29
0
        private unsafe Bitmap BmpFrame()
        {
            Bitmap?bitmap = null;

            if (_iconData != null && _bestBitDepth == 32)
            {
                // GDI+ doesnt handle 32 bpp icons with alpha properly
                // we load the icon ourself from the byte table
                bitmap = new Bitmap(Size.Width, Size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                Debug.Assert(_bestImageOffset >= 0 && (_bestImageOffset + _bestBytesInRes) <= _iconData.Length, "Illegal offset/length for the Icon data");

                unsafe
                {
                    BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height),
                                                         ImageLockMode.WriteOnly,
                                                         PixelFormat.Format32bppArgb);
                    try
                    {
                        uint *pixelPtr = (uint *)bmpdata.Scan0.ToPointer();

                        // jumping the image header
                        int newOffset = (int)(_bestImageOffset + sizeof(NativeMethods.BITMAPINFOHEADER));
                        // there is no color table that we need to skip since we're 32bpp

                        int lineLength = Size.Width * 4;
                        int width      = Size.Width;
                        for (int j = (Size.Height - 1) * 4; j >= 0; j -= 4)
                        {
                            Marshal.Copy(_iconData, newOffset + j * width, (IntPtr)pixelPtr, lineLength);
                            pixelPtr += width;
                        }

                        // note: we ignore the mask that's available after the pixel table
                    }
                    finally
                    {
                        bitmap.UnlockBits(bmpdata);
                    }
                }
            }
            else if (_bestBitDepth == 0 || _bestBitDepth == 32)
            {
                // This may be a 32bpp icon or an icon without any data.
                SafeNativeMethods.ICONINFO info = default;
                SafeNativeMethods.GetIconInfo(new HandleRef(this, _handle), ref info);
                SafeNativeMethods.BITMAP bmp = default;
                try
                {
                    if (info.hbmColor != IntPtr.Zero)
                    {
                        SafeNativeMethods.GetObject(new HandleRef(null, info.hbmColor), sizeof(SafeNativeMethods.BITMAP), ref bmp);
                        if (bmp.bmBitsPixel == 32)
                        {
                            Bitmap?    tmpBitmap  = null;
                            BitmapData?bmpData    = null;
                            BitmapData?targetData = null;
                            try
                            {
                                tmpBitmap = Image.FromHbitmap(info.hbmColor);

                                // In GDI+ the bits are there but the bitmap was created with no alpha channel
                                // so copy the bits by hand to a new bitmap
                                // we also need to go around a limitation in the way the ICON is stored (ie if it's another bpp
                                // but stored in 32bpp all pixels are transparent and not opaque)
                                // (Here you mostly need to remain calm....)
                                bmpData = tmpBitmap.LockBits(new Rectangle(0, 0, tmpBitmap.Width, tmpBitmap.Height), ImageLockMode.ReadOnly, tmpBitmap.PixelFormat);

                                // we need do the following if the image has alpha because otherwise the image is fully transparent even though it has data
                                if (BitmapHasAlpha(bmpData))
                                {
                                    bitmap     = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb);
                                    targetData = bitmap.LockBits(new Rectangle(0, 0, bmpData.Width, bmpData.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

                                    CopyBitmapData(bmpData, targetData);
                                }
                            }
                            finally
                            {
                                if (tmpBitmap != null && bmpData != null)
                                {
                                    tmpBitmap.UnlockBits(bmpData);
                                }
                                if (bitmap != null && targetData != null)
                                {
                                    bitmap.UnlockBits(targetData);
                                }
                            }
                            tmpBitmap.Dispose();
                        }
                    }
                }
                finally
                {
                    if (info.hbmColor != IntPtr.Zero)
                    {
                        Interop.Gdi32.DeleteObject(info.hbmColor);
                    }
                    if (info.hbmMask != IntPtr.Zero)
                    {
                        Interop.Gdi32.DeleteObject(info.hbmMask);
                    }
                }
            }


            if (bitmap == null)
            {
                // last chance... all the other cases (ie non 32 bpp icons coming from a handle or from the bitmapData)

                // we have to do this rather than just return Bitmap.FromHIcon because
                // the bitmap returned from that, even though it's 32bpp, just paints where the mask allows it
                // seems like another GDI+ weirdness. might be interesting to investigate further. In the meantime
                // this looks like the right thing to do and is not more expansive that what was present before.

                Size size = Size;
                bitmap = new Bitmap(size.Width, size.Height); // initialized to transparent
                Graphics?graphics = null;
                using (graphics = Graphics.FromImage(bitmap))
                {
                    try
                    {
                        using (Bitmap tmpBitmap = Bitmap.FromHicon(Handle))
                        {
                            graphics.DrawImage(tmpBitmap, new Rectangle(0, 0, size.Width, size.Height));
                        }
                    }
                    catch (ArgumentException)
                    {
                        // Sometimes FromHicon will crash with no real reason.
                        // The backup plan is to just draw the image like we used to.
                        // NOTE: FromHIcon is also where we have the buffer overrun
                        // if width and height are mismatched.
                        Draw(graphics, new Rectangle(0, 0, size.Width, size.Height));
                    }
                }


                // GDI+ fills the surface with a sentinel color for GetDC, but does
                // not correctly clean it up again, so we have to do it.
                Color fakeTransparencyColor = Color.FromArgb(0x0d, 0x0b, 0x0c);
                bitmap.MakeTransparent(fakeTransparencyColor);
            }

            Debug.Assert(bitmap != null, "Bitmap cannot be null");
            return(bitmap);
        }
예제 #30
0
        public List <RenderableGlyph> LayoutText(Graphics graphics, string?text, Font font, RectangleF drawLayout, StringFormat?format)
        {
            var output = new List <RenderableGlyph>();

            if (text == null)
            {
                return(output);
            }

            // set the current graphics
            _graphics = graphics;

            // set the current text
            _text = text;

            // set the current font
            _font = font;

            // set the current layout rectangle
            layout = drawLayout;

            // set the current string format
            _format = format ?? _defaultStringFormat;

            // set the default hotkey index
            hotkeyIndex = -1;

            // set the current line height
            lineHeight = font.Height;
            if (lineHeight < 1)
            {
                throw new Exception("Invalid line height");
            }

            // set the only whole lines flag
            onlyWholeLines = (_format.FormatFlags & StringFormatFlags.LineLimit) != 0 ||
                             _format.Trimming != StringTrimming.None;


            nextIndex       = 0;
            lineSpaceUsedUp = 0;
            lineNumber      = 0;
            glyphNumber     = 0;

            // set the previous span ended in new line flag
            prevIsNewLine = false;

            // select the current font into the graphics context
            graphics.SelectFont(font);

            // set the current text start
            int textStart = 0;

            // set the current text length
            int textLength = 0;

            // set the current text width
            int textWidth = 0;

            // get the actual hotkey index, if needed
            if (_format.HotkeyPrefix != HotkeyPrefix.None)
            {
                // get the hotkey index
                hotkeyIndex = text.IndexOf('&');

                // handle the hotkey as needed
                if (hotkeyIndex != -1)
                {
                    if (hotkeyIndex >= (text.Length - 1) ||
                        char.IsControl(text[hotkeyIndex + 1]))
                    {
                        // no need for this anymore
                        hotkeyIndex = -1;
                    }
                    else
                    {
                        // remove the hotkey character
                        text = text.Substring(0, hotkeyIndex) +
                               text.Substring(hotkeyIndex + 1);

                        // set the current text
                        _text = text;

                        // prepare to show or hide the underline
                        if (_format.HotkeyPrefix == HotkeyPrefix.Show)
                        {
                            // get the underline font
                            _underlineFont = new Font
                                                 (font, font.Style | FontStyle.Underline);
                        }
                        else
                        {
                            // no need for this anymore
                            hotkeyIndex = -1;
                        }
                    }
                }
            }

            // layout the text
            try
            {
                // handle drawing based on line alignment
                if (_format.LineAlignment == StringAlignment.Near)
                {
                    // set the current y position
                    var y = layout.Top;

                    // get the maximum y position
                    var maxY = layout.Bottom;

                    // adjust for whole lines, if needed
                    if (onlyWholeLines)
                    {
                        maxY -= ((maxY - y) % lineHeight);
                    }

                    // get the last line y position
                    var lastLineY = maxY - lineHeight;

                    // create character spans
                    CharSpan span = new();
                    CharSpan prev = new();

                    // set the first span flag
                    bool firstSpan = true;

                    // process the text
                    while (nextIndex < text.Length)
                    {
                        // get the next span of characters
                        GetNextSpan(span);

                        // draw the pending line, as needed
                        if (span.newline && !firstSpan)
                        {
                            // draw the line, if needed
                            if (textWidth > 0)
                            {
                                // remove trailing spaces, if needed
                                if (!firstSpan && text[prev.start] == ' ')
                                {
                                    // update text width
                                    textWidth -= GetSpanWidth(prev);

                                    // update text length
                                    textLength -= prev.length;
                                }

                                // draw the line
                                DrawLine(output, textStart, textLength, textWidth, y, (y > lastLineY));
                            }

                            // update the y position
                            y += lineHeight;

                            // update the line number
                            ++lineNumber;

                            // update the text start
                            textStart = span.start;

                            // reset the text length
                            textLength = 0;

                            // reset the text width
                            textWidth = 0;
                        }

                        // update the text length
                        textLength += span.length;

                        // update the text width
                        textWidth += GetSpanWidth(span);

                        // copy span values to previous span
                        span.CopyTo(prev);

                        // set the first span flag
                        firstSpan = false;

                        // break if the y position is out of bounds
                        if (y > maxY)
                        {
                            break;
                        }
                    }

                    // draw the last line, if needed
                    if (textWidth > 0 && y <= maxY)
                    {
                        // draw the last line
                        DrawLine(output, textStart, textLength, textWidth, y, (y > lastLineY));
                    }
                }
                else
                {
                    // set default lines to draw
                    int linesToDraw;

                    // calculate lines to draw
                    if (onlyWholeLines)
                    {
                        linesToDraw = (int)Math.Floor((double)layout.Height / lineHeight);
                    }
                    else
                    {
                        linesToDraw = (int)Math.Ceiling((double)layout.Height / lineHeight);
                    }

                    // create line span list
                    LineSpan[] lines = new LineSpan[linesToDraw];

                    // create character spans
                    CharSpan span = new();
                    CharSpan prev = new();

                    // set the first span flag
                    bool firstSpan = true;

                    // set the current line position
                    int linePos = 0;

                    // populate line span list
                    while (linePos < lines.Length &&
                           nextIndex < text.Length)
                    {
                        // get the next span of characters
                        GetNextSpan(span);

                        // handle span on new line
                        if (span.newline && !firstSpan)
                        {
                            // remove trailing spaces, if needed
                            if (!firstSpan && text[prev.start] == ' ')
                            {
                                // update text width
                                textWidth -= GetSpanWidth(prev);

                                // update text length
                                textLength -= prev.length;
                            }

                            // create line span for current line
                            LineSpan lineSpan = new LineSpan
                                                    (textStart, textLength, textWidth);

                            // add current line span to line span list
                            lines[linePos++] = lineSpan;

                            // update text start
                            textStart = span.start;

                            // update text length
                            textLength = 0;

                            // update text width
                            textWidth = 0;
                        }

                        // update text length
                        textLength += span.length;

                        // update text width
                        textWidth += GetSpanWidth(span);

                        // copy span values to previous span
                        span.CopyTo(prev);

                        // set the first span flag
                        firstSpan = false;
                    }

                    // add the last line to the line span list
                    if (linePos < lines.Length)
                    {
                        // create line span for last line
                        LineSpan lineSpan = new LineSpan
                                                (textStart, textLength, textWidth);

                        // add last line span to the line span list
                        lines[linePos++] = lineSpan;
                    }

                    // calculate the top line y
                    var y = (layout.Height - (linePos * lineHeight));

                    // adjust y for center alignment, if needed
                    if (_format.LineAlignment == StringAlignment.Center)
                    {
                        y /= 2;
                    }

                    // translate y to layout rectangle
                    y += layout.Top;

                    // adjust line position to last line
                    --linePos;

                    // draw the lines
                    for (int i = 0; i < linePos; ++i)
                    {
                        // get the current line
                        LineSpan line = lines[i];

                        // draw the current line
                        DrawLine(output, line.start, line.length, line.pixelWidth, y, false);

                        // update the y position
                        y += lineHeight;
                    }

                    // draw the last line
                    DrawLine(output, lines[linePos].start, lines[linePos].length, lines[linePos].pixelWidth, y, true);
                }
            }
            finally
            {
                // dispose the underline font, if we have one
                if (_underlineFont != null)
                {
                    // dispose the underline font
                    _underlineFont.Dispose();

                    // reset the underline font
                    _underlineFont = null;
                }
            }

            return(output);
        }