diff options
author | Larry Ewing <lewing@microsoft.com> | 2020-01-29 07:12:08 +0300 |
---|---|---|
committer | Larry Ewing <lewing@microsoft.com> | 2020-01-29 07:17:07 +0300 |
commit | c6e9369de28efedd4271bfcd78409b822c1b71b3 (patch) | |
tree | 3af429072fadd46959da9ebb2bff3b9e8d1e99de | |
parent | edfe20ffc74dc1918a8fc3416a37404a9ad3d35b (diff) | |
parent | 883162e861c95b7be7c3e830f1d70ff1c8e74fa9 (diff) |
Merge remote-tracking branch 'upstream/master' into checkpoint
36 files changed, 2689 insertions, 2487 deletions
diff --git a/external/api-snapshot b/external/api-snapshot -Subproject c58c68d3c0c70ff011912fbc310da665dbd80c6 +Subproject 5b8247e289d17cef9ff645e21d896ea75bfe632 diff --git a/external/bockbuild b/external/bockbuild -Subproject 839376573f9bac380ee81e8b23c6e2618a779e2 +Subproject 5a05db67cb14844eaafe8070eb425685df6aa9e diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charcode.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charcode.cs deleted file mode 100644 index fc9ca63b12e..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charcode.cs +++ /dev/null @@ -1,413 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -using System.Collections; - -namespace System.Windows.Forms.RTF { - internal class Charcode { - #region Local Variables - private StandardCharCode[] codes; - private Hashtable reverse; - private int size; - #endregion // Local Variables - - #region Cached Values - static Charcode ansi_generic; - #endregion - - #region Public Constructors - public Charcode() : this(256) { - } - - private Charcode(int size) { - this.size = size; - this.codes = new StandardCharCode[size]; - this.reverse = new Hashtable(size); - - // No need to reinitialize array to its default value - //for (int i = 0; i < size; i++) { - // codes[i] = StandardCharCode.nothing; - //} - } - #endregion // Public Constructors - - #region Public Instance Properties - public int this[StandardCharCode c] { - get { - object obj; - - obj = reverse[c]; - if (obj != null) { - return (int)obj; - } - for (int i = 0; i < size; i++) { - if (codes[i] == c) { - return i; - } - } - - return -1; - } - } - - public StandardCharCode this[int c] { - get { - if (c < 0 || c >= size) { - return StandardCharCode.nothing; - } - - return codes[c]; - } - - private set { - if (c < 0 || c >= size) { - return; - } - - codes[c] = value; - reverse[value] = c; - } - } - #endregion // Public Instance Properties - - #region Public Instance Methods - #endregion // Public Instance Methods - - #region Public Static Methods - public static Charcode AnsiGeneric { - get { - if (ansi_generic != null) - return ansi_generic; - - ansi_generic = new Charcode(256); - - ansi_generic[0x06] = StandardCharCode.formula; - ansi_generic[0x1e] = StandardCharCode.nobrkhyphen; - ansi_generic[0x1f] = StandardCharCode.opthyphen; - ansi_generic[' '] = StandardCharCode.space; - ansi_generic['!'] = StandardCharCode.exclam; - ansi_generic['"'] = StandardCharCode.quotedbl; - ansi_generic['#'] = StandardCharCode.numbersign; - ansi_generic['$'] = StandardCharCode.dollar; - ansi_generic['%'] = StandardCharCode.percent; - ansi_generic['&'] = StandardCharCode.ampersand; - ansi_generic['\\'] = StandardCharCode.quoteright; - ansi_generic['('] = StandardCharCode.parenleft; - ansi_generic[')'] = StandardCharCode.parenright; - ansi_generic['*'] = StandardCharCode.asterisk; - ansi_generic['+'] = StandardCharCode.plus; - ansi_generic[','] = StandardCharCode.comma; - ansi_generic['-'] = StandardCharCode.hyphen; - ansi_generic['.'] = StandardCharCode.period; - ansi_generic['/'] = StandardCharCode.slash; - ansi_generic['0'] = StandardCharCode.zero; - ansi_generic['1'] = StandardCharCode.one; - ansi_generic['2'] = StandardCharCode.two; - ansi_generic['3'] = StandardCharCode.three; - ansi_generic['4'] = StandardCharCode.four; - ansi_generic['5'] = StandardCharCode.five; - ansi_generic['6'] = StandardCharCode.six; - ansi_generic['7'] = StandardCharCode.seven; - ansi_generic['8'] = StandardCharCode.eight; - ansi_generic['9'] = StandardCharCode.nine; - ansi_generic[':'] = StandardCharCode.colon; - ansi_generic[';'] = StandardCharCode.semicolon; - ansi_generic['<'] = StandardCharCode.less; - ansi_generic['='] = StandardCharCode.equal; - ansi_generic['>'] = StandardCharCode.greater; - ansi_generic['?'] = StandardCharCode.question; - ansi_generic['@'] = StandardCharCode.at; - ansi_generic['A'] = StandardCharCode.A; - ansi_generic['B'] = StandardCharCode.B; - ansi_generic['C'] = StandardCharCode.C; - ansi_generic['D'] = StandardCharCode.D; - ansi_generic['E'] = StandardCharCode.E; - ansi_generic['F'] = StandardCharCode.F; - ansi_generic['G'] = StandardCharCode.G; - ansi_generic['H'] = StandardCharCode.H; - ansi_generic['I'] = StandardCharCode.I; - ansi_generic['J'] = StandardCharCode.J; - ansi_generic['K'] = StandardCharCode.K; - ansi_generic['L'] = StandardCharCode.L; - ansi_generic['M'] = StandardCharCode.M; - ansi_generic['N'] = StandardCharCode.N; - ansi_generic['O'] = StandardCharCode.O; - ansi_generic['P'] = StandardCharCode.P; - ansi_generic['Q'] = StandardCharCode.Q; - ansi_generic['R'] = StandardCharCode.R; - ansi_generic['S'] = StandardCharCode.S; - ansi_generic['T'] = StandardCharCode.T; - ansi_generic['U'] = StandardCharCode.U; - ansi_generic['V'] = StandardCharCode.V; - ansi_generic['W'] = StandardCharCode.W; - ansi_generic['X'] = StandardCharCode.X; - ansi_generic['Y'] = StandardCharCode.Y; - ansi_generic['Z'] = StandardCharCode.Z; - ansi_generic['['] = StandardCharCode.bracketleft; - ansi_generic['\\'] = StandardCharCode.backslash; - ansi_generic[']'] = StandardCharCode.bracketright; - ansi_generic['^'] = StandardCharCode.asciicircum; - ansi_generic['_'] = StandardCharCode.underscore; - ansi_generic['`'] = StandardCharCode.quoteleft; - ansi_generic['a'] = StandardCharCode.a; - ansi_generic['b'] = StandardCharCode.b; - ansi_generic['c'] = StandardCharCode.c; - ansi_generic['d'] = StandardCharCode.d; - ansi_generic['e'] = StandardCharCode.e; - ansi_generic['f'] = StandardCharCode.f; - ansi_generic['g'] = StandardCharCode.g; - ansi_generic['h'] = StandardCharCode.h; - ansi_generic['i'] = StandardCharCode.i; - ansi_generic['j'] = StandardCharCode.j; - ansi_generic['k'] = StandardCharCode.k; - ansi_generic['l'] = StandardCharCode.l; - ansi_generic['m'] = StandardCharCode.m; - ansi_generic['n'] = StandardCharCode.n; - ansi_generic['o'] = StandardCharCode.o; - ansi_generic['p'] = StandardCharCode.p; - ansi_generic['q'] = StandardCharCode.q; - ansi_generic['r'] = StandardCharCode.r; - ansi_generic['s'] = StandardCharCode.s; - ansi_generic['t'] = StandardCharCode.t; - ansi_generic['u'] = StandardCharCode.u; - ansi_generic['v'] = StandardCharCode.v; - ansi_generic['w'] = StandardCharCode.w; - ansi_generic['x'] = StandardCharCode.x; - ansi_generic['y'] = StandardCharCode.y; - ansi_generic['z'] = StandardCharCode.z; - ansi_generic['{'] = StandardCharCode.braceleft; - ansi_generic['|'] = StandardCharCode.bar; - ansi_generic['}'] = StandardCharCode.braceright; - ansi_generic['~'] = StandardCharCode.asciitilde; - ansi_generic[0xa0] = StandardCharCode.nobrkspace; - ansi_generic[0xa1] = StandardCharCode.exclamdown; - ansi_generic[0xa2] = StandardCharCode.cent; - ansi_generic[0xa3] = StandardCharCode.sterling; - ansi_generic[0xa4] = StandardCharCode.currency; - ansi_generic[0xa5] = StandardCharCode.yen; - ansi_generic[0xa6] = StandardCharCode.brokenbar; - ansi_generic[0xa7] = StandardCharCode.section; - ansi_generic[0xa8] = StandardCharCode.dieresis; - ansi_generic[0xa9] = StandardCharCode.copyright; - ansi_generic[0xaa] = StandardCharCode.ordfeminine; - ansi_generic[0xab] = StandardCharCode.guillemotleft; - ansi_generic[0xac] = StandardCharCode.logicalnot; - ansi_generic[0xad] = StandardCharCode.opthyphen; - ansi_generic[0xae] = StandardCharCode.registered; - ansi_generic[0xaf] = StandardCharCode.macron; - ansi_generic[0xb0] = StandardCharCode.degree; - ansi_generic[0xb1] = StandardCharCode.plusminus; - ansi_generic[0xb2] = StandardCharCode.twosuperior; - ansi_generic[0xb3] = StandardCharCode.threesuperior; - ansi_generic[0xb4] = StandardCharCode.acute; - ansi_generic[0xb5] = StandardCharCode.mu; - ansi_generic[0xb6] = StandardCharCode.paragraph; - ansi_generic[0xb7] = StandardCharCode.periodcentered; - ansi_generic[0xb8] = StandardCharCode.cedilla; - ansi_generic[0xb9] = StandardCharCode.onesuperior; - ansi_generic[0xba] = StandardCharCode.ordmasculine; - ansi_generic[0xbb] = StandardCharCode.guillemotright; - ansi_generic[0xbc] = StandardCharCode.onequarter; - ansi_generic[0xbd] = StandardCharCode.onehalf; - ansi_generic[0xbe] = StandardCharCode.threequarters; - ansi_generic[0xbf] = StandardCharCode.questiondown; - ansi_generic[0xc0] = StandardCharCode.Agrave; - ansi_generic[0xc1] = StandardCharCode.Aacute; - ansi_generic[0xc2] = StandardCharCode.Acircumflex; - ansi_generic[0xc3] = StandardCharCode.Atilde; - ansi_generic[0xc4] = StandardCharCode.Adieresis; - ansi_generic[0xc5] = StandardCharCode.Aring; - ansi_generic[0xc6] = StandardCharCode.AE; - ansi_generic[0xc7] = StandardCharCode.Ccedilla; - ansi_generic[0xc8] = StandardCharCode.Egrave; - ansi_generic[0xc9] = StandardCharCode.Eacute; - ansi_generic[0xca] = StandardCharCode.Ecircumflex; - ansi_generic[0xcb] = StandardCharCode.Edieresis; - ansi_generic[0xcc] = StandardCharCode.Igrave; - ansi_generic[0xcd] = StandardCharCode.Iacute; - ansi_generic[0xce] = StandardCharCode.Icircumflex; - ansi_generic[0xcf] = StandardCharCode.Idieresis; - ansi_generic[0xd0] = StandardCharCode.Eth; - ansi_generic[0xd1] = StandardCharCode.Ntilde; - ansi_generic[0xd2] = StandardCharCode.Ograve; - ansi_generic[0xd3] = StandardCharCode.Oacute; - ansi_generic[0xd4] = StandardCharCode.Ocircumflex; - ansi_generic[0xd5] = StandardCharCode.Otilde; - ansi_generic[0xd6] = StandardCharCode.Odieresis; - ansi_generic[0xd7] = StandardCharCode.multiply; - ansi_generic[0xd8] = StandardCharCode.Oslash; - ansi_generic[0xd9] = StandardCharCode.Ugrave; - ansi_generic[0xda] = StandardCharCode.Uacute; - ansi_generic[0xdb] = StandardCharCode.Ucircumflex; - ansi_generic[0xdc] = StandardCharCode.Udieresis; - ansi_generic[0xdd] = StandardCharCode.Yacute; - ansi_generic[0xde] = StandardCharCode.Thorn; - ansi_generic[0xdf] = StandardCharCode.germandbls; - ansi_generic[0xe0] = StandardCharCode.agrave; - ansi_generic[0xe1] = StandardCharCode.aacute; - ansi_generic[0xe2] = StandardCharCode.acircumflex; - ansi_generic[0xe3] = StandardCharCode.atilde; - ansi_generic[0xe4] = StandardCharCode.adieresis; - ansi_generic[0xe5] = StandardCharCode.aring; - ansi_generic[0xe6] = StandardCharCode.ae; - ansi_generic[0xe7] = StandardCharCode.ccedilla; - ansi_generic[0xe8] = StandardCharCode.egrave; - ansi_generic[0xe9] = StandardCharCode.eacute; - ansi_generic[0xea] = StandardCharCode.ecircumflex; - ansi_generic[0xeb] = StandardCharCode.edieresis; - ansi_generic[0xec] = StandardCharCode.igrave; - ansi_generic[0xed] = StandardCharCode.iacute; - ansi_generic[0xee] = StandardCharCode.icircumflex; - ansi_generic[0xef] = StandardCharCode.idieresis; - ansi_generic[0xf0] = StandardCharCode.eth; - ansi_generic[0xf1] = StandardCharCode.ntilde; - ansi_generic[0xf2] = StandardCharCode.ograve; - ansi_generic[0xf3] = StandardCharCode.oacute; - ansi_generic[0xf4] = StandardCharCode.ocircumflex; - ansi_generic[0xf5] = StandardCharCode.otilde; - ansi_generic[0xf6] = StandardCharCode.odieresis; - ansi_generic[0xf7] = StandardCharCode.divide; - ansi_generic[0xf8] = StandardCharCode.oslash; - ansi_generic[0xf9] = StandardCharCode.ugrave; - ansi_generic[0xfa] = StandardCharCode.uacute; - ansi_generic[0xfb] = StandardCharCode.ucircumflex; - ansi_generic[0xfc] = StandardCharCode.udieresis; - ansi_generic[0xfd] = StandardCharCode.yacute; - ansi_generic[0xfe] = StandardCharCode.thorn; - ansi_generic[0xff] = StandardCharCode.ydieresis; - - return ansi_generic; - } - } - - public static Charcode AnsiSymbol { - get { - Charcode code = new Charcode(256); - - code[0x06] = StandardCharCode.formula; - code[0x1e] = StandardCharCode.nobrkhyphen; - code[0x1f] = StandardCharCode.opthyphen; - code[' '] = StandardCharCode.space; - code['!'] = StandardCharCode.exclam; - code['"'] = StandardCharCode.universal; - code['#'] = StandardCharCode.mathnumbersign; - code['$'] = StandardCharCode.existential; - code['%'] = StandardCharCode.percent; - code['&'] = StandardCharCode.ampersand; - code['\\'] = StandardCharCode.suchthat; - code['('] = StandardCharCode.parenleft; - code[')'] = StandardCharCode.parenright; - code['*'] = StandardCharCode.mathasterisk; - code['+'] = StandardCharCode.mathplus; - code[','] = StandardCharCode.comma; - code['-'] = StandardCharCode.mathminus; - code['.'] = StandardCharCode.period; - code['/'] = StandardCharCode.slash; - code['0'] = StandardCharCode.zero; - code['1'] = StandardCharCode.one; - code['2'] = StandardCharCode.two; - code['3'] = StandardCharCode.three; - code['4'] = StandardCharCode.four; - code['5'] = StandardCharCode.five; - code['6'] = StandardCharCode.six; - code['7'] = StandardCharCode.seven; - code['8'] = StandardCharCode.eight; - code['9'] = StandardCharCode.nine; - code[':'] = StandardCharCode.colon; - code[';'] = StandardCharCode.semicolon; - code['<'] = StandardCharCode.less; - code['='] = StandardCharCode.mathequal; - code['>'] = StandardCharCode.greater; - code['?'] = StandardCharCode.question; - code['@'] = StandardCharCode.congruent; - code['A'] = StandardCharCode.Alpha; - code['B'] = StandardCharCode.Beta; - code['C'] = StandardCharCode.Chi; - code['D'] = StandardCharCode.Delta; - code['E'] = StandardCharCode.Epsilon; - code['F'] = StandardCharCode.Phi; - code['G'] = StandardCharCode.Gamma; - code['H'] = StandardCharCode.Eta; - code['I'] = StandardCharCode.Iota; - code['K'] = StandardCharCode.Kappa; - code['L'] = StandardCharCode.Lambda; - code['M'] = StandardCharCode.Mu; - code['N'] = StandardCharCode.Nu; - code['O'] = StandardCharCode.Omicron; - code['P'] = StandardCharCode.Pi; - code['Q'] = StandardCharCode.Theta; - code['R'] = StandardCharCode.Rho; - code['S'] = StandardCharCode.Sigma; - code['T'] = StandardCharCode.Tau; - code['U'] = StandardCharCode.Upsilon; - code['V'] = StandardCharCode.varsigma; - code['W'] = StandardCharCode.Omega; - code['X'] = StandardCharCode.Xi; - code['Y'] = StandardCharCode.Psi; - code['Z'] = StandardCharCode.Zeta; - code['['] = StandardCharCode.bracketleft; - code['\\'] = StandardCharCode.backslash; - code[']'] = StandardCharCode.bracketright; - code['^'] = StandardCharCode.asciicircum; - code['_'] = StandardCharCode.underscore; - code['`'] = StandardCharCode.quoteleft; - code['a'] = StandardCharCode.alpha; - code['b'] = StandardCharCode.beta; - code['c'] = StandardCharCode.chi; - code['d'] = StandardCharCode.delta; - code['e'] = StandardCharCode.epsilon; - code['f'] = StandardCharCode.phi; - code['g'] = StandardCharCode.gamma; - code['h'] = StandardCharCode.eta; - code['i'] = StandardCharCode.iota; - code['k'] = StandardCharCode.kappa; - code['l'] = StandardCharCode.lambda; - code['m'] = StandardCharCode.mu; - code['n'] = StandardCharCode.nu; - code['o'] = StandardCharCode.omicron; - code['p'] = StandardCharCode.pi; - code['q'] = StandardCharCode.theta; - code['r'] = StandardCharCode.rho; - code['s'] = StandardCharCode.sigma; - code['t'] = StandardCharCode.tau; - code['u'] = StandardCharCode.upsilon; - code['w'] = StandardCharCode.omega; - code['x'] = StandardCharCode.xi; - code['y'] = StandardCharCode.psi; - code['z'] = StandardCharCode.zeta; - code['{'] = StandardCharCode.braceleft; - code['|'] = StandardCharCode.bar; - code['}'] = StandardCharCode.braceright; - code['~'] = StandardCharCode.mathtilde; - - return code; - } - } - #endregion // Public Static Methods - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charset.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charset.cs deleted file mode 100644 index cba57819595..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charset.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -using System; - -// COMPLETE - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - class Charset { - #region Local Variables - private CharsetType id; - private CharsetFlags flags; - private Charcode code; - private string file; - #endregion // Local Variables - - #region Public Constructors - public Charset() { - flags = CharsetFlags.Read | CharsetFlags.Switch; - id = CharsetType.General; - file = string.Empty; - this.ReadMap(); - } - #endregion // Public Constructors - - #region Public Instance Properties - public Charcode Code { - get { - return code; - } - - set { - code = value; - } - } - - public CharsetFlags Flags { - get { - return flags; - } - - set { - flags = value; - } - } - - public CharsetType ID { - get { - return id; - } - - set { - switch(value) { - case CharsetType.Symbol: { - id = CharsetType.Symbol; - return; - } - - default: - case CharsetType.General: { - id = CharsetType.General; - return; - } - } - } - } - - public string File { - get { - return file; - } - - set { - if (file != value) { - file = value; - } - } - } - - public StandardCharCode this[int c] { - get { - return code[c]; - } - } - - #endregion // Public Instance Properties - - #region Public Instance Methods - public bool ReadMap() { - switch (id) { - case CharsetType.General: { - if (file == string.Empty) { - code = Charcode.AnsiGeneric; - return true; - } - // FIXME - implement reading charmap from file... - return true; - } - - case CharsetType.Symbol: { - if (file == string.Empty) { - code = Charcode.AnsiSymbol; - return true; - } - - // FIXME - implement reading charmap from file... - return true; - } - - default: { - return false; - } - } - } - - public char StdCharCode(string name) { - // FIXME - finish this - return ' '; - - } - - public string StdCharName(char code) { - // FIXME - finish this - return String.Empty; - } - #endregion // Public Instance Methods - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetFlags.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetFlags.cs deleted file mode 100644 index 7cfcb8c6539..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetFlags.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -namespace System.Windows.Forms.RTF { - [Flags] -#if RTF_LIB - public -#else - internal -#endif - enum CharsetFlags { - None = 0x00, - Read = 0x01, - Switch = 0x02 - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetToCodepage.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetToCodepage.cs new file mode 100644 index 00000000000..783c6351007 --- /dev/null +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetToCodepage.cs @@ -0,0 +1,79 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2020 Karl Scowen +// +// Authors: +// Karl Scowen <contact@scowencomputers.co.nz> +// +// + + +namespace System.Windows.Forms.RTF { + internal static class CharsetToCodepage { + public static int Translate(CharsetType charset) + { + switch (charset) { + case CharsetType.General: + case CharsetType.Arabic_Traditional: + case CharsetType.Arabic_user: + case CharsetType.Hebrew_user: + case CharsetType.Mac: // Technically wrong, because "mac" should actually be quite a few with their own code pages... + default: + return System.Text.Encoding.Default.CodePage; + case CharsetType.ANSI: + return 1252; + case CharsetType.Symbol: + return 42; + case CharsetType.Shift_Jis: + return 932; + case CharsetType.Hangul: + return 949; + case CharsetType.Johab: + return 1361; + case CharsetType.GB2312: + return 936; + case CharsetType.Big5: + return 950; + case CharsetType.Greek: + return 1253; + case CharsetType.Turkish: + return 1254; + case CharsetType.Vietnamese: + return 1258; + case CharsetType.Hebrew: + return 1255; + case CharsetType.Arabic: + return 1256; + case CharsetType.Baltic: + return 1257; + case CharsetType.Russian: + return 1251; + case CharsetType.Thai: + return 874; + case CharsetType.Eastern_European: + return 1250; + case CharsetType.PC_437: + return 437; + case CharsetType.OEM: + return 850; + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs index a934dc82869..4dbb3d94897 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok (pbartok@novell.com) +// Karl Scowen (contact@scowencomputers.co.nz) // // @@ -33,8 +34,29 @@ namespace System.Windows.Forms.RTF { #else internal #endif - enum CharsetType { - General = 0, - Symbol = 1, + enum CharsetType : byte { + ANSI = 0, + General = 1, + Symbol = 2, + Mac = 77, + Shift_Jis = 128, + Hangul = 129, + Johab = 130, + GB2312 = 134, + Big5 = 136, + Greek = 161, + Turkish = 162, + Vietnamese = 163, + Hebrew = 177, + Arabic = 178, + Arabic_Traditional = 179, + Arabic_user = 180, + Hebrew_user = 181, + Baltic = 186, + Russian = 204, + Thai = 222, + Eastern_European = 238, + PC_437 = 254, + OEM = 255 } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs index 72188e6daa7..5ff3ff426c6 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs @@ -366,10 +366,12 @@ namespace System.Windows.Forms.RTF { new KeyStruct(Major.StyleAttr, Minor.Next, "snext"), new KeyStruct(Major.PictAttr, Minor.MacQD, "macpict"), new KeyStruct(Major.PictAttr, Minor.PMMetafile, "pmmetafile"), + new KeyStruct(Major.PictAttr, Minor.EnhancedMetafile, "emfblip"), new KeyStruct(Major.PictAttr, Minor.WinMetafile, "wmetafile"), new KeyStruct(Major.PictAttr, Minor.DevIndBitmap, "dibitmap"), new KeyStruct(Major.PictAttr, Minor.WinBitmap, "wbitmap"), new KeyStruct(Major.PictAttr, Minor.PngBlip, "pngblip"), + new KeyStruct(Major.PictAttr, Minor.JpegBlip, "jpgblip"), new KeyStruct(Major.PictAttr, Minor.PixelBits, "wbmbitspixel"), new KeyStruct(Major.PictAttr, Minor.BitmapPlanes, "wbmplanes"), new KeyStruct(Major.PictAttr, Minor.BitmapWid, "wbmwidthbytes"), @@ -393,6 +395,7 @@ namespace System.Windows.Forms.RTF { new KeyStruct(Major.NeXTGrAttr, Minor.NeXTGHeight, "height"), new KeyStruct(Major.Destination, Minor.OptDest, "*"), new KeyStruct(Major.Destination, Minor.FontTbl, "fonttbl"), + new KeyStruct(Major.Destination, Minor.FontName, "fname"), new KeyStruct(Major.Destination, Minor.FontAltName, "falt"), new KeyStruct(Major.Destination, Minor.EmbeddedFont, "fonteb"), new KeyStruct(Major.Destination, Minor.FontFile, "fontfile"), diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs index 8b0f1bc6f8d..4033f5bbf24 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs @@ -41,6 +41,7 @@ namespace System.Windows.Forms.RTF { // Major.Destinan FontTbl, + FontName, FontAltName, EmbeddedFont, FontFile, @@ -520,10 +521,12 @@ namespace System.Windows.Forms.RTF { // Major.PictAttr MacQD, PMMetafile, + EnhancedMetafile, WinMetafile, DevIndBitmap, WinBitmap, PngBlip, + JpegBlip, PixelBits, BitmapPlanes, BitmapWid, diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs index 244bcd9adff..35845b20aff 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs @@ -66,7 +66,7 @@ namespace System.Windows.Forms.RTF { public float Width { get { float w = width; - if (w == -1) { + if (w < 0) { if (image == null) image = ToImage (); w = image.Width; @@ -79,7 +79,7 @@ namespace System.Windows.Forms.RTF { public float Height { get { float h = height; - if (h == -1) { + if (h < 0) { if (image == null) image = ToImage (); h = image.Height; @@ -113,7 +113,9 @@ namespace System.Windows.Forms.RTF { return false; switch (image_type) { case Minor.PngBlip: + case Minor.JpegBlip: case Minor.WinMetafile: + case Minor.EnhancedMetafile: break; default: return false; @@ -126,15 +128,7 @@ namespace System.Windows.Forms.RTF { { if (image == null) image = ToImage (); - - float height = this.height; - float width = this.width; - - if (height == -1) - height = image.Height; - if (width == -1) - width = image.Width; - dc.DrawImage (image, x, y, width, height); + dc.DrawImage (image, x, y, Width, Height); } public Image ToImage () diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs index 3b02df81ffb..469c379ed2b 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok (pbartok@novell.com) +// Karl Scowen <contact@scowencomputers.co.nz> // // COMPLETE @@ -60,10 +61,6 @@ namespace System.Windows.Forms.RTF { private char prev_char; private bool bump_line; - - private Font font_list; - - private Charset cur_charset; private Stack charset_stack; private Style styles; @@ -101,10 +98,7 @@ namespace System.Windows.Forms.RTF { line_pos = 0; prev_char = unchecked((char)-1); bump_line = false; - font_list = null; - charset_stack = null; - - cur_charset = new Charset(); + charset_stack = new Stack(); destination_callbacks = new DestinationCallback(); class_callbacks = new ClassCallback(); @@ -369,49 +363,52 @@ SkipCRLF: GetToken2(); if (this.rtf_class == TokenClass.Text) { - this.minor = (Minor)this.cur_charset[(int)this.major]; - if (encoding == null) { + if (encoding == null) encoding = Encoding.GetEncoding (encoding_code_page); - } encoded_text = new String (encoding.GetChars (new byte [] { (byte) this.major })); - } - - if (this.cur_charset.Flags == CharsetFlags.None) { - return this.rtf_class; - } - - if (CheckCMM (TokenClass.Control, Major.Unicode, Minor.UnicodeAnsiCodepage)) { + } else if (CheckCMM (TokenClass.Control, Major.Unicode, Minor.UnicodeAnsiCodepage)) { encoding_code_page = param; // fallback to the default one in case we have an invalid value if (encoding_code_page < 0 || encoding_code_page > 65535) encoding_code_page = DefaultEncodingCodePage; - } - if (((this.cur_charset.Flags & CharsetFlags.Read) != 0) && CheckCM(TokenClass.Control, Major.CharSet)) { - this.cur_charset.ReadMap(); - } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) { + encoding = null; + } else if (CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) { Font fp; - fp = Font.GetFont(this.font_list, this.param); + fp = Font.GetFont(this.fonts, this.param); if (fp != null) { - if (fp.Name.StartsWith("Symbol")) { - this.cur_charset.ID = CharsetType.Symbol; + if (fp.Codepage != 0) { + if (fp.Codepage != encoding_code_page) { + encoding_code_page = fp.Codepage; + encoding = null; + } } else { - this.cur_charset.ID = CharsetType.General; - } - } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && (this.rtf_class == TokenClass.Group)) { - switch(this.major) { - case Major.BeginGroup: { - this.charset_stack.Push(this.cur_charset); - break; + var cp = CharsetToCodepage.Translate (fp.Charset); + if (cp != 0 && cp != encoding_code_page) { + encoding_code_page = cp; + encoding = null; } + } + } + } else if (this.rtf_class == TokenClass.Group) { + switch(this.major) { + case Major.BeginGroup: { + charset_stack.Push(encoding_code_page); + break; + } - case Major.EndGroup: { - this.cur_charset = (Charset)this.charset_stack.Pop(); - break; + case Major.EndGroup: { + if (charset_stack.Count > 0) { + encoding_code_page = (int)this.charset_stack.Pop(); + } else { + encoding_code_page = DefaultEncodingCodePage; } + if (encoding != null && encoding.CodePage != encoding_code_page) + encoding = null; + break; } } } @@ -677,7 +674,10 @@ SkipCRLF: font = new Font(rtf); - while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) { + int depth = 0; + string untaggedName = null; + + while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && depth >= 0) { if (rtf.rtf_class == TokenClass.Control) { switch(rtf.major) { case Major.FontFamily: { @@ -734,6 +734,26 @@ SkipCRLF: break; } + case Major.Destination: { + switch (rtf.minor) { + case Minor.FontName: + untaggedName = ReadFontName (rtf); + break; + + case Minor.FontAltName: + font.AltName = ReadFontName (rtf); + break; + + default: { + #if RTF_DEBUG + Console.WriteLine ("Got unhandled Control.Destination.Minor: " + rtf.minor); + #endif + break; + } + } + break; + } + default: { #if RTF_DEBUG Console.WriteLine("ReadFontTbl: Unknown Control token " + rtf.major); @@ -742,22 +762,12 @@ SkipCRLF: } } } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { - rtf.SkipGroup(); - } else if (rtf.rtf_class == TokenClass.Text) { - StringBuilder sb; - - sb = new StringBuilder(); - - while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup))) { - sb.Append((char)rtf.major); - rtf.GetToken(); - } - - if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { - rtf.UngetToken(); - } - - font.Name = sb.ToString(); + depth++; + } else if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + depth--; + } else if (rtf.rtf_class == TokenClass.Text) + { + font.Name = ReadFontName (rtf); continue; #if RTF_DEBUG } else { @@ -768,6 +778,9 @@ SkipCRLF: rtf.GetToken(); } + if (untaggedName != null) + font.Name = untaggedName; + if (old == 0) { rtf.GetToken(); @@ -788,6 +801,26 @@ SkipCRLF: rtf.RouteToken(); } + private static String ReadFontName(RTF rtf) + { + StringBuilder sb = new StringBuilder (); + + while (rtf.rtf_class != TokenClass.EOF && rtf.rtf_class != TokenClass.Text) + rtf.GetToken (); + + while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM (TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && + (!rtf.CheckCM (TokenClass.Group, Major.BeginGroup))) { + sb.Append ((char)rtf.major); + rtf.GetToken (); + } + + if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) { + rtf.UngetToken(); + } + + return sb.ToString (); + } + private void ReadColorTbl(RTF rtf) { Color color; int num; @@ -943,20 +976,25 @@ SkipCRLF: private void ReadPictGroup(RTF rtf) { bool read_image_data = false; - + int groupDepth = 0; Picture picture = new Picture (); while (true) { rtf.GetToken (); + if (rtf.CheckCM (TokenClass.Group, Major.BeginGroup)) + groupDepth++; + if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) + groupDepth--; + + if (groupDepth < 0) break; switch (minor) { case Minor.PngBlip: - picture.ImageType = minor; - read_image_data = true; - break; + case Minor.JpegBlip: case Minor.WinMetafile: + case Minor.EnhancedMetafile: picture.ImageType = minor; read_image_data = true; continue; @@ -1047,10 +1085,33 @@ SkipCRLF: } } - private void ReadObjGroup(RTF rtf) { - rtf.SkipGroup(); - rtf.RouteToken(); + private void ReadObjGroup (RTF rtf) + { + int level; + + level = 1; + + while (GetToken () != TokenClass.EOF && this.minor != Minor.ObjResult) { + if (rtf_class == TokenClass.Group) { + if (this.major == Major.BeginGroup) { + level++; + } else if (this.major == Major.EndGroup) { + level--; + if (level < 1) { + break; + } + } + } + } + + if (level >= 1) { + GetToken (); + + if (rtf_class == TokenClass.Group) + GetToken (); + rtf.RouteToken (); + } } #endregion // Default Delegates } -} + } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharCode.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharCode.cs deleted file mode 100644 index 906735ba181..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharCode.cs +++ /dev/null @@ -1,392 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - enum StandardCharCode { - nothing = 0, - space = 1, - exclam = 2, - quotedbl = 3, - numbersign = 4, - dollar = 5, - percent = 6, - ampersand = 7, - quoteright = 8, - parenleft = 9, - parenright = 10, - asterisk = 11, - plus = 12, - comma = 13, - hyphen = 14, - period = 15, - slash = 16, - zero = 17, - one = 18, - two = 19, - three = 20, - four = 21, - five = 22, - six = 23, - seven = 24, - eight = 25, - nine = 26, - colon = 27, - semicolon = 28, - less = 29, - equal = 30, - greater = 31, - question = 32, - at = 33, - A = 34, - B = 35, - C = 36, - D = 37, - E = 38, - F = 39, - G = 40, - H = 41, - I = 42, - J = 43, - K = 44, - L = 45, - M = 46, - N = 47, - O = 48, - P = 49, - Q = 50, - R = 51, - S = 52, - T = 53, - U = 54, - V = 55, - W = 56, - X = 57, - Y = 58, - Z = 59, - bracketleft = 60, - backslash = 61, - bracketright = 62, - asciicircum = 63, - underscore = 64, - quoteleft = 65, - a = 66, - b = 67, - c = 68, - d = 69, - e = 70, - f = 71, - g = 72, - h = 73, - i = 74, - j = 75, - k = 76, - l = 77, - m = 78, - n = 79, - o = 80, - p = 81, - q = 82, - r = 83, - s = 84, - t = 85, - u = 86, - v = 87, - w = 88, - x = 89, - y = 90, - z = 91, - braceleft = 92, - bar = 93, - braceright = 94, - asciitilde = 95, - exclamdown = 96, - cent = 97, - sterling = 98, - fraction = 99, - yen = 100, - florin = 101, - section = 102, - currency = 103, - quotedblleft = 104, - guillemotleft = 105, - guilsinglleft = 106, - guilsinglright = 107, - fi = 108, - fl = 109, - endash = 110, - dagger = 111, - daggerdbl = 112, - periodcentered = 113, - paragraph = 114, - bullet = 115, - quotesinglbase = 116, - quotedblbase = 117, - quotedblright = 118, - guillemotright = 119, - ellipsis = 120, - perthousand = 121, - questiondown = 122, - grave = 123, - acute = 124, - circumflex = 125, - tilde = 126, - macron = 127, - breve = 128, - dotaccent = 129, - dieresis = 130, - ring = 131, - cedilla = 132, - hungarumlaut = 133, - ogonek = 134, - caron = 135, - emdash = 136, - AE = 137, - ordfeminine = 138, - Lslash = 139, - Oslash = 140, - OE = 141, - ordmasculine = 142, - ae = 143, - dotlessi = 144, - lslash = 145, - oslash = 146, - oe = 147, - germandbls = 148, - Aacute = 149, - Acircumflex = 150, - Adieresis = 151, - Agrave = 152, - Aring = 153, - Atilde = 154, - Ccedilla = 155, - Eacute = 156, - Ecircumflex = 157, - Edieresis = 158, - Egrave = 159, - Eth = 160, - Iacute = 161, - Icircumflex = 162, - Idieresis = 163, - Igrave = 164, - Ntilde = 165, - Oacute = 166, - Ocircumflex = 167, - Odieresis = 168, - Ograve = 169, - Otilde = 170, - Scaron = 171, - Thorn = 172, - Uacute = 173, - Ucircumflex = 174, - Udieresis = 175, - Ugrave = 176, - Yacute = 177, - Ydieresis = 178, - aacute = 179, - acircumflex = 180, - adieresis = 181, - agrave = 182, - aring = 183, - atilde = 184, - brokenbar = 185, - ccedilla = 186, - copyright = 187, - degree = 188, - divide = 189, - eacute = 190, - ecircumflex = 191, - edieresis = 192, - egrave = 193, - eth = 194, - iacute = 195, - icircumflex = 196, - idieresis = 197, - igrave = 198, - logicalnot = 199, - minus = 200, - multiply = 201, - ntilde = 202, - oacute = 203, - ocircumflex = 204, - odieresis = 205, - ograve = 206, - onehalf = 207, - onequarter = 208, - onesuperior = 209, - otilde = 210, - plusminus = 211, - registered = 212, - thorn = 213, - threequarters = 214, - threesuperior = 215, - trademark = 216, - twosuperior = 217, - uacute = 218, - ucircumflex = 219, - udieresis = 220, - ugrave = 221, - yacute = 222, - ydieresis = 223, - Alpha = 224, - Beta = 225, - Chi = 226, - Delta = 227, - Epsilon = 228, - Phi = 229, - Gamma = 230, - Eta = 231, - Iota = 232, - Kappa = 233, - Lambda = 234, - Mu = 235, - Nu = 236, - Omicron = 237, - Pi = 238, - Theta = 239, - Rho = 240, - Sigma = 241, - Tau = 242, - Upsilon = 243, - varUpsilon = 244, - Omega = 245, - Xi = 246, - Psi = 247, - Zeta = 248, - alpha = 249, - beta = 250, - chi = 251, - delta = 252, - epsilon = 253, - phi = 254, - varphi = 255, - gamma = 256, - eta = 257, - iota = 258, - kappa = 259, - lambda = 260, - mu = 261, - nu = 262, - omicron = 263, - pi = 264, - varpi = 265, - theta = 266, - vartheta = 267, - rho = 268, - sigma = 269, - varsigma = 270, - tau = 271, - upsilon = 272, - omega = 273, - xi = 274, - psi = 275, - zeta = 276, - nobrkspace = 277, - nobrkhyphen = 278, - lessequal = 279, - greaterequal = 280, - infinity = 281, - integral = 282, - notequal = 283, - radical = 284, - radicalex = 285, - approxequal = 286, - apple = 287, - partialdiff = 288, - opthyphen = 289, - formula = 290, - lozenge = 291, - universal = 292, - existential = 293, - suchthat = 294, - congruent = 295, - therefore = 296, - perpendicular = 297, - minute = 298, - club = 299, - diamond = 300, - heart = 301, - spade = 302, - arrowboth = 303, - arrowleft = 304, - arrowup = 305, - arrowright = 306, - arrowdown = 307, - second = 308, - proportional = 309, - equivalence = 310, - arrowvertex = 311, - arrowhorizex = 312, - carriagereturn = 313, - aleph = 314, - Ifraktur = 315, - Rfraktur = 316, - weierstrass = 317, - circlemultiply = 318, - circleplus = 319, - emptyset = 320, - intersection = 321, - union = 322, - propersuperset = 323, - reflexsuperset = 324, - notsubset = 325, - propersubset = 326, - reflexsubset = 327, - element = 328, - notelement = 329, - angle = 330, - gradient = 331, - product = 332, - logicaland = 333, - logicalor = 334, - arrowdblboth = 335, - arrowdblleft = 336, - arrowdblup = 337, - arrowdblright = 338, - arrowdbldown = 339, - angleleft = 340, - registersans = 341, - copyrightsans = 342, - trademarksans = 343, - angleright = 344, - mathplus = 345, - mathminus = 346, - mathasterisk = 347, - mathnumbersign = 348, - dotmath = 349, - mathequal = 350, - mathtilde = 351, - - MaxChar = 352 - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharName.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharName.cs deleted file mode 100644 index 0190b798cf2..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharName.cs +++ /dev/null @@ -1,411 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - class StandardCharName { - public static string[] Names = { - "nothing", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Eth", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Thorn", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "brokenbar", - "ccedilla", - "copyright", - "degree", - "divide", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "eth", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "logicalnot", - "minus", - "multiply", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "onehalf", - "onequarter", - "onesuperior", - "otilde", - "plusminus", - "registered", - "thorn", - "threequarters", - "threesuperior", - "trademark", - "twosuperior", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "Alpha", - "Beta", - "Chi", - "Delta", - "Epsilon", - "Phi", - "Gamma", - "Eta", - "Iota", - "Kappa", - "Lambda", - "Mu", - "Nu", - "Omicron", - "Pi", - "Theta", - "Rho", - "Sigma", - "Tau", - "Upsilon", - "varUpsilon", - "Omega", - "Xi", - "Psi", - "Zeta", - "alpha", - "beta", - "chi", - "delta", - "epsilon", - "phi", - "varphi", - "gamma", - "eta", - "iota", - "kappa", - "lambda", - "mu", - "nu", - "omicron", - "pi", - "varpi", - "theta", - "vartheta", - "rho", - "sigma", - "varsigma", - "tau", - "upsilon", - "omega", - "xi", - "psi", - "zeta", - "nobrkspace", - "nobrkhyphen", - "lessequal", - "greaterequal", - "infinity", - "integral", - "notequal", - "radical", - "radicalex", - "approxequal", - "apple", - "partialdiff", - "opthyphen", - "formula", - "lozenge", - "universal", - "existential", - "suchthat", - "congruent", - "therefore", - "perpendicular", - "minute", - "club", - "diamond", - "heart", - "spade", - "arrowboth", - "arrowleft", - "arrowup", - "arrowright", - "arrowdown", - "second", - "proportional", - "equivalence", - "arrowvertex", - "arrowhorizex", - "carriagereturn", - "aleph", - "Ifraktur", - "Rfraktur", - "weierstrass", - "circlemultiply", - "circleplus", - "emptyset", - "intersection", - "union", - "propersuperset", - "reflexsuperset", - "notsubset", - "propersubset", - "reflexsubset", - "element", - "notelement", - "angle", - "gradient", - "product", - "logicaland", - "logicalor", - "arrowdblboth", - "arrowdblleft", - "arrowdblup", - "arrowdblright", - "arrowdbldown", - "angleleft", - "registersans", - "copyrightsans", - "trademarksans", - "angleright", - "mathplus", - "mathminus", - "mathasterisk", - "mathnumbersign", - "dotmath", - "mathequal", - "mathtilde" - }; - - /// <summary>Lookup name by ID</summary> - public static string Name(int index) { - if ((index < 0) || (index >= Names.Length)) { - return string.Empty; - } - - return Names[index]; - } - - /// <summary>Lookup ID by name (e.g. mathtilde)</summary> - public static int ID(string name) { - for (int i=0; i < Names.Length; i++) { - if (name.Equals(Names[i])) { - return i; - } - } - return 0; - } - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/TextMap.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/TextMap.cs deleted file mode 100644 index f4474b92627..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/TextMap.cs +++ /dev/null @@ -1,440 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// This map is for convencience only, any app can create/use it's own -// StdCharCode -> <text> table - -using System.Collections; - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - class TextMap { - #region Local Variables - private string[] table; - #endregion // Local Variables - - #region Public Constructors - public TextMap() { - table = new string[(int)StandardCharCode.MaxChar]; - - for (int i = 0; i < (int)StandardCharCode.MaxChar; i++) { - table[i] = string.Empty; - } - } - #endregion // Public Constructors - - #region Public Instance Properties - internal string this[StandardCharCode c] { // FIXME - this should be public, if the whole namespace was public (ie standalone RTF parser) - get { - return table[(int)c]; - } - - set { - table[(int)c] = value; - } - } - - public string[] Table { - get { - return table; - } - } - #endregion // Public Instance Properties - - #region Public Static Methods - public static void SetupStandardTable(string[] table) - { - /* - table[(int)StandardCharCode.space] = " "; - table[(int)StandardCharCode.exclam] = "!"; - table[(int)StandardCharCode.quotedbl] = "\""; - table[(int)StandardCharCode.numbersign] = "#"; - table[(int)StandardCharCode.dollar] = "$"; - table[(int)StandardCharCode.percent] = "%"; - table[(int)StandardCharCode.ampersand] = "&"; - table[(int)StandardCharCode.quoteright] = "'"; - table[(int)StandardCharCode.parenleft] = "("; - table[(int)StandardCharCode.parenright] = ")"; - table[(int)StandardCharCode.asterisk] = "*"; - table[(int)StandardCharCode.plus] = "+"; - table[(int)StandardCharCode.comma] = ","; - table[(int)StandardCharCode.hyphen] = "-"; - table[(int)StandardCharCode.period] = "."; - table[(int)StandardCharCode.slash] = "/"; - table[(int)StandardCharCode.zero] = "0"; - table[(int)StandardCharCode.one] = "1"; - table[(int)StandardCharCode.two] = "2"; - table[(int)StandardCharCode.three] = "3"; - table[(int)StandardCharCode.four] = "4"; - table[(int)StandardCharCode.five] = "5"; - table[(int)StandardCharCode.six] = "6"; - table[(int)StandardCharCode.seven] = "7"; - table[(int)StandardCharCode.eight] = "8"; - table[(int)StandardCharCode.nine] = "9"; - table[(int)StandardCharCode.colon] = ":"; - table[(int)StandardCharCode.semicolon] = ";"; - table[(int)StandardCharCode.less] = "<"; - table[(int)StandardCharCode.equal] = "="; - table[(int)StandardCharCode.greater] = ">"; - table[(int)StandardCharCode.question] = "?"; - table[(int)StandardCharCode.at] = "@"; - table[(int)StandardCharCode.A] = "A"; - table[(int)StandardCharCode.B] = "B"; - table[(int)StandardCharCode.C] = "C"; - table[(int)StandardCharCode.D] = "D"; - table[(int)StandardCharCode.E] = "E"; - table[(int)StandardCharCode.F] = "F"; - table[(int)StandardCharCode.G] = "G"; - table[(int)StandardCharCode.H] = "H"; - table[(int)StandardCharCode.I] = "I"; - table[(int)StandardCharCode.J] = "J"; - table[(int)StandardCharCode.K] = "K"; - table[(int)StandardCharCode.L] = "L"; - table[(int)StandardCharCode.M] = "M"; - table[(int)StandardCharCode.N] = "N"; - table[(int)StandardCharCode.O] = "O"; - table[(int)StandardCharCode.P] = "P"; - table[(int)StandardCharCode.Q] = "Q"; - table[(int)StandardCharCode.R] = "R"; - table[(int)StandardCharCode.S] = "S"; - table[(int)StandardCharCode.T] = "T"; - table[(int)StandardCharCode.U] = "U"; - table[(int)StandardCharCode.V] = "V"; - table[(int)StandardCharCode.W] = "W"; - table[(int)StandardCharCode.X] = "X"; - table[(int)StandardCharCode.Y] = "Y"; - table[(int)StandardCharCode.Z] = "Z"; - table[(int)StandardCharCode.bracketleft] = "["; - table[(int)StandardCharCode.backslash] = "\\"; - table[(int)StandardCharCode.bracketright] = "]"; - table[(int)StandardCharCode.asciicircum] = "^"; - table[(int)StandardCharCode.underscore] = "_"; - table[(int)StandardCharCode.quoteleft] = "`"; - table[(int)StandardCharCode.a] = "a"; - table[(int)StandardCharCode.b] = "b"; - table[(int)StandardCharCode.c] = "c"; - table[(int)StandardCharCode.d] = "d"; - table[(int)StandardCharCode.e] = "e"; - table[(int)StandardCharCode.f] = "f"; - table[(int)StandardCharCode.g] = "g"; - table[(int)StandardCharCode.h] = "h"; - table[(int)StandardCharCode.i] = "i"; - table[(int)StandardCharCode.j] = "j"; - table[(int)StandardCharCode.k] = "k"; - table[(int)StandardCharCode.l] = "l"; - table[(int)StandardCharCode.m] = "m"; - table[(int)StandardCharCode.n] = "n"; - table[(int)StandardCharCode.o] = "o"; - table[(int)StandardCharCode.p] = "p"; - table[(int)StandardCharCode.q] = "q"; - table[(int)StandardCharCode.r] = "r"; - table[(int)StandardCharCode.s] = "s"; - table[(int)StandardCharCode.t] = "t"; - table[(int)StandardCharCode.u] = "u"; - table[(int)StandardCharCode.v] = "v"; - table[(int)StandardCharCode.w] = "w"; - table[(int)StandardCharCode.x] = "x"; - table[(int)StandardCharCode.y] = "y"; - table[(int)StandardCharCode.z] = "z"; - table[(int)StandardCharCode.braceleft] = "{"; - table[(int)StandardCharCode.bar] = "|"; - table[(int)StandardCharCode.braceright] = "}"; - table[(int)StandardCharCode.asciitilde] = "~"; - table[(int)StandardCharCode.AE] = "AE"; - table[(int)StandardCharCode.OE] = "OE"; - table[(int)StandardCharCode.acute] = "'"; - table[(int)StandardCharCode.ae] = "ae"; - table[(int)StandardCharCode.angleleft] = "<"; - table[(int)StandardCharCode.angleright] = ">"; - table[(int)StandardCharCode.arrowboth] = "<->"; - table[(int)StandardCharCode.arrowdblboth] = "<=>"; - table[(int)StandardCharCode.arrowdblleft] = "<="; - table[(int)StandardCharCode.arrowdblright] = "=>"; - table[(int)StandardCharCode.arrowleft] = "<-"; - table[(int)StandardCharCode.arrowright] = "->"; - table[(int)StandardCharCode.bullet] = "o"; - table[(int)StandardCharCode.cent] = "cent"; - table[(int)StandardCharCode.circumflex] = "^"; - table[(int)StandardCharCode.copyright] = "(c)"; - table[(int)StandardCharCode.copyrightsans] = "(c)"; - table[(int)StandardCharCode.degree] = "deg."; - table[(int)StandardCharCode.divide] = "/"; - table[(int)StandardCharCode.dotlessi] = "i"; - table[(int)StandardCharCode.ellipsis] = "..."; - table[(int)StandardCharCode.emdash] = "--"; - table[(int)StandardCharCode.endash] = "-"; - table[(int)StandardCharCode.fi] = "fi"; - table[(int)StandardCharCode.fl] = "fl"; - table[(int)StandardCharCode.fraction] = "/"; - table[(int)StandardCharCode.germandbls] = "ss"; - table[(int)StandardCharCode.grave] = "`"; - table[(int)StandardCharCode.greaterequal] = ">="; - table[(int)StandardCharCode.guillemotleft] = "<<"; - table[(int)StandardCharCode.guillemotright] = ">>"; - table[(int)StandardCharCode.guilsinglleft] = "<"; - table[(int)StandardCharCode.guilsinglright] = ">"; - table[(int)StandardCharCode.lessequal] = "<="; - table[(int)StandardCharCode.logicalnot] = "~"; - table[(int)StandardCharCode.mathasterisk] = "*"; - table[(int)StandardCharCode.mathequal] = "="; - table[(int)StandardCharCode.mathminus] = "-"; - table[(int)StandardCharCode.mathnumbersign] = "#"; - table[(int)StandardCharCode.mathplus] = "+"; - table[(int)StandardCharCode.mathtilde] = "~"; - table[(int)StandardCharCode.minus] = "-"; - table[(int)StandardCharCode.mu] = "u"; - table[(int)StandardCharCode.multiply] = "x"; - table[(int)StandardCharCode.nobrkhyphen] = "-"; - table[(int)StandardCharCode.nobrkspace] = ""; - table[(int)StandardCharCode.notequal] = "!="; - table[(int)StandardCharCode.oe] = "oe"; - table[(int)StandardCharCode.onehalf] = "1/2"; - table[(int)StandardCharCode.onequarter] = "1/4"; - table[(int)StandardCharCode.periodcentered] = "."; - table[(int)StandardCharCode.plusminus] = "+/-"; - table[(int)StandardCharCode.quotedblbase] = ",,"; - table[(int)StandardCharCode.quotedblleft] = "\""; - table[(int)StandardCharCode.quotedblright] = "\""; - table[(int)StandardCharCode.quotesinglbase] = ","; - table[(int)StandardCharCode.registered] = "reg."; - table[(int)StandardCharCode.registersans] = "reg."; - table[(int)StandardCharCode.threequarters] = "3/4"; - table[(int)StandardCharCode.tilde] = "~"; - table[(int)StandardCharCode.trademark] = "(TM)"; - table[(int)StandardCharCode.trademarksans] = "(TM)"; - - table[(int)StandardCharCode.aacute] = "\xE0"; - table[(int)StandardCharCode.questiondown] = "\xBF"; - - table[(int)StandardCharCode.udieresis] = "\xFC"; - table[(int)StandardCharCode.Udieresis] = "\xDC"; - table[(int)StandardCharCode.odieresis] = "\xF6"; - table[(int)StandardCharCode.Odieresis] = "\xD6"; - */ - - table [(int) StandardCharCode.formula] = "\x6"; - table [(int) StandardCharCode.nobrkhyphen] = "\x1e"; - table [(int) StandardCharCode.opthyphen] = "\x1f"; - table [(int) StandardCharCode.space] = " "; - table [(int) StandardCharCode.exclam] = "!"; - table [(int) StandardCharCode.quotedbl] = "\""; - table [(int) StandardCharCode.numbersign] = "#"; - table [(int) StandardCharCode.dollar] = "$"; - table [(int) StandardCharCode.percent] = "%"; - table [(int) StandardCharCode.ampersand] = "&"; - table [(int) StandardCharCode.parenleft] = "("; - table [(int) StandardCharCode.parenright] = ")"; - table [(int) StandardCharCode.asterisk] = "*"; - table [(int) StandardCharCode.plus] = "+"; - table [(int) StandardCharCode.comma] = ","; - table [(int) StandardCharCode.hyphen] = "-"; - table [(int) StandardCharCode.period] = "."; - table [(int) StandardCharCode.slash] = "/"; - table [(int) StandardCharCode.zero] = "0"; - table [(int) StandardCharCode.one] = "1"; - table [(int) StandardCharCode.two] = "2"; - table [(int) StandardCharCode.three] = "3"; - table [(int) StandardCharCode.four] = "4"; - table [(int) StandardCharCode.five] = "5"; - table [(int) StandardCharCode.six] = "6"; - table [(int) StandardCharCode.seven] = "7"; - table [(int) StandardCharCode.eight] = "8"; - table [(int) StandardCharCode.nine] = "9"; - table [(int) StandardCharCode.colon] = ":"; - table [(int) StandardCharCode.semicolon] = ";"; - table [(int) StandardCharCode.less] = "<"; - table [(int) StandardCharCode.equal] = "="; - table [(int) StandardCharCode.greater] = ">"; - table [(int) StandardCharCode.question] = "?"; - table [(int) StandardCharCode.at] = "@"; - table [(int) StandardCharCode.A] = "A"; - table [(int) StandardCharCode.B] = "B"; - table [(int) StandardCharCode.C] = "C"; - table [(int) StandardCharCode.D] = "D"; - table [(int) StandardCharCode.E] = "E"; - table [(int) StandardCharCode.F] = "F"; - table [(int) StandardCharCode.G] = "G"; - table [(int) StandardCharCode.H] = "H"; - table [(int) StandardCharCode.I] = "I"; - table [(int) StandardCharCode.J] = "J"; - table [(int) StandardCharCode.K] = "K"; - table [(int) StandardCharCode.L] = "L"; - table [(int) StandardCharCode.M] = "M"; - table [(int) StandardCharCode.N] = "N"; - table [(int) StandardCharCode.O] = "O"; - table [(int) StandardCharCode.P] = "P"; - table [(int) StandardCharCode.Q] = "Q"; - table [(int) StandardCharCode.R] = "R"; - table [(int) StandardCharCode.S] = "S"; - table [(int) StandardCharCode.T] = "T"; - table [(int) StandardCharCode.U] = "U"; - table [(int) StandardCharCode.V] = "V"; - table [(int) StandardCharCode.W] = "W"; - table [(int) StandardCharCode.X] = "X"; - table [(int) StandardCharCode.Y] = "Y"; - table [(int) StandardCharCode.Z] = "Z"; - table [(int) StandardCharCode.bracketleft] = "["; - table [(int) StandardCharCode.backslash] = "\\"; - table [(int) StandardCharCode.bracketright] = "]"; - table [(int) StandardCharCode.asciicircum] = "^"; - table [(int) StandardCharCode.underscore] = "_"; - table [(int) StandardCharCode.quoteleft] = "`"; - table [(int) StandardCharCode.a] = "a"; - table [(int) StandardCharCode.b] = "b"; - table [(int) StandardCharCode.c] = "c"; - table [(int) StandardCharCode.d] = "d"; - table [(int) StandardCharCode.e] = "e"; - table [(int) StandardCharCode.f] = "f"; - table [(int) StandardCharCode.g] = "g"; - table [(int) StandardCharCode.h] = "h"; - table [(int) StandardCharCode.i] = "i"; - table [(int) StandardCharCode.j] = "j"; - table [(int) StandardCharCode.k] = "k"; - table [(int) StandardCharCode.l] = "l"; - table [(int) StandardCharCode.m] = "m"; - table [(int) StandardCharCode.n] = "n"; - table [(int) StandardCharCode.o] = "o"; - table [(int) StandardCharCode.p] = "p"; - table [(int) StandardCharCode.q] = "q"; - table [(int) StandardCharCode.r] = "r"; - table [(int) StandardCharCode.s] = "s"; - table [(int) StandardCharCode.t] = "t"; - table [(int) StandardCharCode.u] = "u"; - table [(int) StandardCharCode.v] = "v"; - table [(int) StandardCharCode.w] = "w"; - table [(int) StandardCharCode.x] = "x"; - table [(int) StandardCharCode.y] = "y"; - table [(int) StandardCharCode.z] = "z"; - table [(int) StandardCharCode.braceleft] = "{"; - table [(int) StandardCharCode.bar] = "|"; - table [(int) StandardCharCode.braceright] = "}"; - table [(int) StandardCharCode.asciitilde] = "~"; - table [(int) StandardCharCode.nobrkspace] = "\xa0"; - table [(int) StandardCharCode.exclamdown] = "\xa1"; - table [(int) StandardCharCode.cent] = "\xa2"; - table [(int) StandardCharCode.sterling] = "\xa3"; - table [(int) StandardCharCode.currency] = "\xa4"; - table [(int) StandardCharCode.yen] = "\xa5"; - table [(int) StandardCharCode.brokenbar] = "\xa6"; - table [(int) StandardCharCode.section] = "\xa7"; - table [(int) StandardCharCode.dieresis] = "\xa8"; - table [(int) StandardCharCode.copyright] = "\xa9"; - table [(int) StandardCharCode.ordfeminine] = "\xaa"; - table [(int) StandardCharCode.guillemotleft] = "\xab"; - table [(int) StandardCharCode.logicalnot] = "\xac"; - table [(int) StandardCharCode.opthyphen] = "\xad"; - table [(int) StandardCharCode.registered] = "\xae"; - table [(int) StandardCharCode.macron] = "\xaf"; - table [(int) StandardCharCode.degree] = "\xb0"; - table [(int) StandardCharCode.plusminus] = "\xb1"; - table [(int) StandardCharCode.twosuperior] = "\xb2"; - table [(int) StandardCharCode.threesuperior] = "\xb3"; - table [(int) StandardCharCode.acute] = "\xb4"; - table [(int) StandardCharCode.mu] = "\xb5"; - table [(int) StandardCharCode.paragraph] = "\xb6"; - table [(int) StandardCharCode.periodcentered] = "\xb7"; - table [(int) StandardCharCode.cedilla] = "\xb8"; - table [(int) StandardCharCode.onesuperior] = "\xb9"; - table [(int) StandardCharCode.ordmasculine] = "\xba"; - table [(int) StandardCharCode.guillemotright] = "\xbb"; - table [(int) StandardCharCode.onequarter] = "\xbc"; - table [(int) StandardCharCode.onehalf] = "\xbd"; - table [(int) StandardCharCode.threequarters] = "\xbe"; - table [(int) StandardCharCode.questiondown] = "\xbf"; - table [(int) StandardCharCode.Agrave] = "\xc0"; - table [(int) StandardCharCode.Aacute] = "\xc1"; - table [(int) StandardCharCode.Acircumflex] = "\xc2"; - table [(int) StandardCharCode.Atilde] = "\xc3"; - table [(int) StandardCharCode.Adieresis] = "\xc4"; - table [(int) StandardCharCode.Aring] = "\xc5"; - table [(int) StandardCharCode.AE] = "\xc6"; - table [(int) StandardCharCode.Ccedilla] = "\xc7"; - table [(int) StandardCharCode.Egrave] = "\xc8"; - table [(int) StandardCharCode.Eacute] = "\xc9"; - table [(int) StandardCharCode.Ecircumflex] = "\xca"; - table [(int) StandardCharCode.Edieresis] = "\xcb"; - table [(int) StandardCharCode.Igrave] = "\xcc"; - table [(int) StandardCharCode.Iacute] = "\xcd"; - table [(int) StandardCharCode.Icircumflex] = "\xce"; - table [(int) StandardCharCode.Idieresis] = "\xcf"; - table [(int) StandardCharCode.Eth] = "\xd0"; - table [(int) StandardCharCode.Ntilde] = "\xd1"; - table [(int) StandardCharCode.Ograve] = "\xd2"; - table [(int) StandardCharCode.Oacute] = "\xd3"; - table [(int) StandardCharCode.Ocircumflex] = "\xd4"; - table [(int) StandardCharCode.Otilde] = "\xd5"; - table [(int) StandardCharCode.Odieresis] = "\xd6"; - table [(int) StandardCharCode.multiply] = "\xd7"; - table [(int) StandardCharCode.Oslash] = "\xd8"; - table [(int) StandardCharCode.Ugrave] = "\xd9"; - table [(int) StandardCharCode.Uacute] = "\xda"; - table [(int) StandardCharCode.Ucircumflex] = "\xdb"; - table [(int) StandardCharCode.Udieresis] = "\xdc"; - table [(int) StandardCharCode.Yacute] = "\xdd"; - table [(int) StandardCharCode.Thorn] = "\xde"; - table [(int) StandardCharCode.germandbls] = "\xdf"; - table [(int) StandardCharCode.agrave] = "\xe0"; - table [(int) StandardCharCode.aacute] = "\xe1"; - table [(int) StandardCharCode.acircumflex] = "\xe2"; - table [(int) StandardCharCode.atilde] = "\xe3"; - table [(int) StandardCharCode.adieresis] = "\xe4"; - table [(int) StandardCharCode.aring] = "\xe5"; - table [(int) StandardCharCode.ae] = "\xe6"; - table [(int) StandardCharCode.ccedilla] = "\xe7"; - table [(int) StandardCharCode.egrave] = "\xe8"; - table [(int) StandardCharCode.eacute] = "\xe9"; - table [(int) StandardCharCode.ecircumflex] = "\xea"; - table [(int) StandardCharCode.edieresis] = "\xeb"; - table [(int) StandardCharCode.igrave] = "\xec"; - table [(int) StandardCharCode.iacute] = "\xed"; - table [(int) StandardCharCode.icircumflex] = "\xee"; - table [(int) StandardCharCode.idieresis] = "\xef"; - table [(int) StandardCharCode.eth] = "\xf0"; - table [(int) StandardCharCode.ntilde] = "\xf1"; - table [(int) StandardCharCode.ograve] = "\xf2"; - table [(int) StandardCharCode.oacute] = "\xf3"; - table [(int) StandardCharCode.ocircumflex] = "\xf4"; - table [(int) StandardCharCode.otilde] = "\xf5"; - table [(int) StandardCharCode.odieresis] = "\xf6"; - table [(int) StandardCharCode.divide] = "\xf7"; - table [(int) StandardCharCode.oslash] = "\xf8"; - table [(int) StandardCharCode.ugrave] = "\xf9"; - table [(int) StandardCharCode.uacute] = "\xfa"; - table [(int) StandardCharCode.ucircumflex] = "\xfb"; - table [(int) StandardCharCode.udieresis] = "\xfc"; - table [(int) StandardCharCode.yacute] = "\xfd"; - table [(int) StandardCharCode.thorn] = "\xfe"; - table [(int) StandardCharCode.ydieresis] = "\xff"; - - } - #endregion // Public Static Methods - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj b/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj index fb32cde820b..f94733d9e20 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj @@ -100,9 +100,7 @@ <Compile Include="System.Windows.Forms.Layout\TableLayout.cs" /> <Compile Include="System.Windows.Forms.Layout\TableLayoutSettingsTypeConverter.cs" /> <Compile Include="System.Windows.Forms.PropertyGridInternal\PropertiesTab.cs" /> - <Compile Include="System.Windows.Forms.RTF\Charcode.cs" /> - <Compile Include="System.Windows.Forms.RTF\Charset.cs" /> - <Compile Include="System.Windows.Forms.RTF\CharsetFlags.cs" /> + <Compile Include="System.Windows.Forms.RTF\CharsetToCodepage.cs" /> <Compile Include="System.Windows.Forms.RTF\CharsetType.cs" /> <Compile Include="System.Windows.Forms.RTF\ClassDelegate.cs" /> <Compile Include="System.Windows.Forms.RTF\Color.cs" /> @@ -115,12 +113,9 @@ <Compile Include="System.Windows.Forms.RTF\Picture.cs" /> <Compile Include="System.Windows.Forms.RTF\RTF.cs" /> <Compile Include="System.Windows.Forms.RTF\RTFException.cs" /> - <Compile Include="System.Windows.Forms.RTF\StandardCharCode.cs" /> - <Compile Include="System.Windows.Forms.RTF\StandardCharName.cs" /> <Compile Include="System.Windows.Forms.RTF\Style.cs" /> <Compile Include="System.Windows.Forms.RTF\StyleElement.cs" /> <Compile Include="System.Windows.Forms.RTF\StyleType.cs" /> - <Compile Include="System.Windows.Forms.RTF\TextMap.cs" /> <Compile Include="System.Windows.Forms.RTF\TokenClass.cs" /> <Compile Include="System.Windows.Forms.Theming\Default\ButtonPainter.cs" /> <Compile Include="System.Windows.Forms.Theming\Default\CheckBoxPainter.cs" /> @@ -787,6 +782,7 @@ <Compile Include="System.Windows.Forms\TabPage.cs" /> <Compile Include="System.Windows.Forms\TabRenderer.cs" /> <Compile Include="System.Windows.Forms\TabSizeMode.cs" /> + <Compile Include="System.Windows.Forms\TabStops.cs" /> <Compile Include="System.Windows.Forms\TableLayoutCellPaintEventArgs.cs" /> <Compile Include="System.Windows.Forms\TableLayoutCellPaintEventHandler.cs" /> <Compile Include="System.Windows.Forms\TableLayoutColumnStyleCollection.cs" /> diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources index 0655e691273..235dd61bed4 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources @@ -29,9 +29,7 @@ System.Windows.Forms.Design/WindowsFormsComponentEditor.cs System.Windows.Forms.Internal/Accessor.cs System.Windows.Forms.Internal/DebugHelper.cs System.Windows.Forms.PropertyGridInternal/PropertiesTab.cs -System.Windows.Forms.RTF/Charcode.cs -System.Windows.Forms.RTF/Charset.cs -System.Windows.Forms.RTF/CharsetFlags.cs +System.Windows.Forms.RTF/CharsetToCodepage.cs System.Windows.Forms.RTF/CharsetType.cs System.Windows.Forms.RTF/ClassDelegate.cs System.Windows.Forms.RTF/Color.cs @@ -44,12 +42,9 @@ System.Windows.Forms.RTF/Minor.cs System.Windows.Forms.RTF/Picture.cs System.Windows.Forms.RTF/RTF.cs System.Windows.Forms.RTF/RTFException.cs -System.Windows.Forms.RTF/StandardCharCode.cs -System.Windows.Forms.RTF/StandardCharName.cs System.Windows.Forms.RTF/Style.cs System.Windows.Forms.RTF/StyleElement.cs System.Windows.Forms.RTF/StyleType.cs -System.Windows.Forms.RTF/TextMap.cs System.Windows.Forms.RTF/TokenClass.cs System.Windows.Forms.Theming/Default/LabelPainter.cs System.Windows.Forms.Theming/Default/LinkLabelPainter.cs @@ -657,6 +652,7 @@ System.Windows.Forms/TableLayoutRowStyleCollection.cs System.Windows.Forms/TableLayoutSettings.cs System.Windows.Forms/TableLayoutStyle.cs System.Windows.Forms/TableLayoutStyleCollection.cs +System.Windows.Forms/TabStops.cs System.Windows.Forms/TextBox.cs System.Windows.Forms/TextBoxBase.cs System.Windows.Forms/TextBoxRenderer.cs diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs index 1df14883d09..c95804739f9 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ContextMenuStrip.cs @@ -35,27 +35,23 @@ namespace System.Windows.Forms [DefaultEvent ("Opening")] public class ContextMenuStrip : ToolStripDropDownMenu { - Control source_control; - internal Control container; + internal Control AssociatedControl; #region Public Construtors public ContextMenuStrip () : base () { - source_control = null; } - public ContextMenuStrip (IContainer container) : base () + public ContextMenuStrip (IContainer container) : this () { - source_control = null; + // TODO: handle `container` argument } #endregion #region Public Properties [Browsable (false)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] - public Control SourceControl { - get { return this.source_control; } - } + public Control SourceControl { get; protected set; } #endregion #region Protected Methods @@ -70,11 +66,12 @@ namespace System.Windows.Forms if (visible) XplatUI.SetTopmost (this.Handle, true); } - #endregion - internal void SetSourceControl (Control source_control) + protected override void SetOwnerControl (Control control) { - container = this.source_control = source_control; + base.SetOwnerControl (control); + SourceControl = control; } + #endregion } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs index ecd8c90e51b..53f489d751b 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Control.cs @@ -1406,8 +1406,7 @@ namespace System.Windows.Forms if (background_image == null) { if (!tbstyle_flat) { Rectangle paintRect = pevent.ClipRectangle; - Brush pen = ThemeEngine.Current.ResPool.GetSolidBrush(BackColor); - pevent.Graphics.FillRectangle(pen, paintRect); + pevent.Graphics.FillRectangle(BackColorBrush, paintRect); } return; } @@ -1417,8 +1416,8 @@ namespace System.Windows.Forms void DrawBackgroundImage (Graphics g) { Rectangle drawing_rectangle = new Rectangle (); - g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle); - + g.FillRectangle (BackColorBrush, ClientRectangle); + switch (backgroundimage_layout) { case ImageLayout.Tile: @@ -2426,7 +2425,7 @@ namespace System.Windows.Forms if (this.context_menu_strip != value) { this.context_menu_strip = value; if (value != null) - value.container = this; + value.AssociatedControl = this; OnContextMenuStripChanged (EventArgs.Empty); } } @@ -3469,6 +3468,8 @@ namespace System.Windows.Forms } } + protected SolidBrush BackColorBrush => ThemeEngine.Current.ResPool.GetSolidBrush (BackColor); + #endregion // Protected Instance Properties #region Public Static Methods @@ -5497,22 +5498,21 @@ namespace System.Windows.Forms return; } - // If there isn't a regular context menu, show the Strip version - if (context_menu == null && context_menu_strip != null) { - Point pt; + // If there isn't a regular context menu, show the Strip version + if (context_menu == null && context_menu_strip != null) { + Point pt; - pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); - - if (pt.X == -1 || pt.Y == -1) { - pt.X = (this.Width / 2) + this.Left; - pt.Y = (this.Height /2) + this.Top; - pt = this.PointToScreen (pt); - } - - context_menu_strip.SetSourceControl (this); - context_menu_strip.Show (this, PointToClient (pt)); - return; + pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ())); + + if (pt.X == -1 || pt.Y == -1) { + pt.X = (this.Width / 2) + this.Left; + pt.Y = (this.Height /2) + this.Top; + pt = this.PointToScreen (pt); } + + context_menu_strip.Show (this, PointToClient (pt)); + return; + } DefWndProc(ref m); } @@ -6499,7 +6499,6 @@ namespace System.Windows.Forms remove { Events.RemoveHandler (ContextMenuStripChangedEvent, value);} } - [EditorBrowsable(EditorBrowsableState.Advanced)] [Browsable(true)] public event ControlEventHandler ControlAdded { diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ControlPaint.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ControlPaint.cs index 4004c1ec8ec..5a933f1dc10 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ControlPaint.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ControlPaint.cs @@ -370,11 +370,11 @@ namespace System.Windows.Forms { ThemeEngine.Current.CPDrawContainerGrabHandle (graphics, bounds); } - public static void DrawFocusRectangle( Graphics graphics, Rectangle rectangle) { + public static void DrawFocusRectangle(Graphics graphics, Rectangle rectangle) { DrawFocusRectangle(graphics, rectangle, SystemColors.Control, SystemColors.ControlText); } - public static void DrawFocusRectangle( Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor) { + public static void DrawFocusRectangle(Graphics graphics, Rectangle rectangle, Color foreColor, Color backColor) { ThemeEngine.Current.CPDrawFocusRectangle (graphics, rectangle, foreColor, backColor); } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs index 7f032754f70..fcd95416024 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Form.cs @@ -201,7 +201,11 @@ namespace System.Windows.Forms { internal override void UpdateWindowText () { + var old_clientsize = ClientSize; + if (!IsHandleCreated) { + if (is_clientsize_set) + ClientSize = old_clientsize; return; } @@ -213,6 +217,9 @@ namespace System.Windows.Forms { } XplatUI.Text (Handle, Text.Replace (Environment.NewLine, string.Empty)); + + if (ClientSize != old_clientsize) + ClientSize = old_clientsize; } internal void SelectActiveControl () @@ -236,7 +243,7 @@ namespace System.Windows.Forms { this.is_visible = visible; } else { - Select (ActiveControl); + SendControlFocus (ActiveControl); } } @@ -596,7 +603,7 @@ namespace System.Windows.Forms { set { if (control_box != value) { control_box = value; - UpdateStyles(); + UpdateFormStyles(); } } } @@ -662,15 +669,10 @@ namespace System.Windows.Forms { window_manager.UpdateBorderStyle (value); } - Size current_client_size = ClientSize; - UpdateStyles(); + UpdateFormStyles(); - if (this.IsHandleCreated) { - this.Size = InternalSizeFromClientSize (current_client_size); + if (this.IsHandleCreated) XplatUI.InvalidateNC (this.Handle); - } else if (is_clientsize_set) { - this.Size = InternalSizeFromClientSize (current_client_size); - } } } @@ -1124,7 +1126,7 @@ namespace System.Windows.Forms { set { if (this.show_icon != value ) { this.show_icon = value; - UpdateStyles (); + UpdateFormStyles (); if (IsHandleCreated) { XplatUI.SetIcon (this.Handle, value == true ? this.Icon : null); @@ -2197,7 +2199,7 @@ namespace System.Windows.Forms { if (keyData == Keys.Enter) { IntPtr window = XplatUI.GetFocus (); Control c = Control.FromHandle (window); - if (c is Button && c.FindForm () == this) { + if (c is Button && c.Visible && c.Enabled && c.FindForm () == this) { ((Button)c).PerformClick (); return true; } @@ -2894,6 +2896,13 @@ namespace System.Windows.Forms { is_loaded = true; } + private void UpdateFormStyles() { + var old_clientsize = ClientSize; + UpdateStyles(); + if ((!IsHandleCreated && is_clientsize_set) || ClientSize != old_clientsize) + ClientSize = old_clientsize; + } + private void UpdateMinMax() { var min_size = AutoSize ? new Size (Math.Max (minimum_auto_size.Width, minimum_size.Width), Math.Max (minimum_auto_size.Height, minimum_size.Height)) : minimum_size; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs index d169d9adfd2..f7f063a8b70 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs @@ -21,6 +21,7 @@ //
// Authors:
// Peter Bartok pbartok@novell.com
+// Karl Scowen <contact@scowencomputers.co.nz>
//
//
@@ -44,14 +45,20 @@ namespace System.Windows.Forms internal int line_no; // Line number
internal LineTag tags; // Tags describing the text
internal int offset; // Baseline can be on the X or Y axis depending if we are in multiline mode or not
- internal int height; // Height of the line (height of tallest tag)
- internal int ascent; // Ascent of the line (ascent of the tallest tag)
+ internal int height; // Total height of the line, including TotalParagraphSpacing and LineSpacing
+ private int textHeight; // Height of the line without spacing.
+ internal int ascent; // Ascent of the line (highest distance above the baseline, including character offset)
internal HorizontalAlignment alignment; // Alignment of the line
internal int align_shift; // Pixel shift caused by the alignment
- internal int indent; // Left indent for the first line
- internal int hanging_indent; // Hanging indent (left indent for all but the first line)
- internal int right_indent; // Right indent for all lines
+ internal float indent; // Left indent for the first line
+ internal float hanging_indent; // Hanging indent (difference between first line indent and other lines)
+ internal float right_indent; // Right indent for all lines
internal LineEnding ending;
+ internal float spacing_before;
+ internal float spacing_after;
+ internal float line_spacing;
+ internal bool line_spacing_multiple;
+ internal TabStopCollection tab_stops; // Custom tabstops for this paragraph.
// Stuff that's important for the tree
internal Line parent; // Our parent line
@@ -86,10 +93,11 @@ namespace System.Windows.Forms text = new StringBuilder (Text, space);
line_no = LineNo;
this.ending = ending;
+ tab_stops = new TabStopCollection();
widths = new float[space + 1];
-
+
tags = new LineTag(this, 1);
tags.Font = font;
tags.Color = color;
@@ -103,6 +111,7 @@ namespace System.Windows.Forms line_no = LineNo;
this.ending = ending;
alignment = align;
+ tab_stops = new TabStopCollection();
widths = new float[space + 1];
@@ -112,6 +121,38 @@ namespace System.Windows.Forms tags.Color = color;
}
+ internal Line (Document document, int LineNo, string Text, HorizontalAlignment align, Font font, Color color,
+ Color back_color, TextPositioning text_position, float char_offset, float left_indent, float hanging_indent,
+ float right_indent, float spacing_before, float spacing_after, float line_spacing, bool line_spacing_multiple,
+ TabStopCollection tab_stops, bool visible, LineEnding ending) : this(document, ending)
+ {
+ space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
+
+ text = new StringBuilder (Text, space);
+ line_no = LineNo;
+ this.ending = ending;
+ alignment = align;
+ indent = left_indent;
+ HangingIndent = hanging_indent;
+ this.right_indent = right_indent;
+ this.spacing_before = spacing_before;
+ this.spacing_after = spacing_after;
+ this.tab_stops = tab_stops;
+ this.line_spacing = line_spacing;
+ this.line_spacing_multiple = line_spacing_multiple;
+
+ widths = new float[space + 1];
+
+
+ tags = new LineTag(this, 1);
+ tags.Font = font;
+ tags.Color = color;
+ tags.BackColor = back_color;
+ tags.TextPosition = text_position;
+ tags.CharOffset = char_offset;
+ tags.Visible = visible;
+ }
+
internal Line (Document document, int LineNo, string Text, LineTag tag, LineEnding ending) : this(document, ending)
{
space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
@@ -137,10 +178,10 @@ namespace System.Windows.Forms }
}
- internal int HangingIndent {
+ internal float HangingIndent {
get { return hanging_indent; }
set {
- hanging_indent = value;
+ this.hanging_indent = value;
recalc = true;
}
}
@@ -151,7 +192,63 @@ namespace System.Windows.Forms set { height = value; }
}
- internal int Indent {
+ internal int TextHeight {
+ get {
+ return textHeight;
+ }
+ }
+
+ internal TabStopCollection TabStops {
+ get { return tab_stops; }
+ set { tab_stops = value; }
+ }
+
+ internal float TotalParagraphSpacing {
+ get {
+ return SpacingBefore + SpacingAfter;
+ }
+ }
+
+ internal float LineSpacing {
+ get {
+ if (textHeight == 0) {
+ throw new InvalidOperationException("Can't get LineSpacing when the line height isn't calculated!");
+ }
+ if (line_spacing < 0) {
+ return -line_spacing;
+ } else if (line_spacing_multiple) {
+ return line_spacing * textHeight * 6f / document.Dpi;
+ } else {
+ return Math.Max(line_spacing, textHeight);
+ }
+ }
+ }
+
+ internal float SpacingBefore {
+ get {
+ bool has_spacing = true;
+ if (line_no > 1) {
+ Line previous_line = document.GetLine(line_no - 1);
+ if (previous_line != null && (previous_line.ending == LineEnding.Wrap || previous_line.ending == LineEnding.None))
+ has_spacing = false;
+ }
+ if (has_spacing)
+ return spacing_before;
+ else
+ return 0;
+ }
+ }
+
+ internal float SpacingAfter {
+ get {
+ if (ending == LineEnding.Wrap)
+ return 0;
+ else
+ return spacing_after;
+ }
+ }
+
+ internal float Indent {
get { return indent; }
set {
indent = value;
@@ -164,7 +261,7 @@ namespace System.Windows.Forms set { line_no = value; }
}
- internal int RightIndent {
+ internal float RightIndent {
get { return right_indent; }
set {
right_indent = value;
@@ -254,7 +351,7 @@ namespace System.Windows.Forms return;
// Find the first tag that we are deleting from
- tag = FindTag (pos + 1);
+ tag = FindTag (pos);
// Remove the characters from the line
text.Remove (pos, count);
@@ -271,10 +368,10 @@ namespace System.Windows.Forms left = count;
left -= tag.Start + tag.Length - pos - 1;
- tag = tag.Next;
// Update the start of each tag
- while ((tag != null) && (left > 0)) {
+ while ((tag.Next != null) && (left > 0)) {
+ tag = tag.Next;
// Cache tag.Length as is will be indireclty modified
// by changes to tag.Start
int tag_length = tag.Length;
@@ -284,7 +381,6 @@ namespace System.Windows.Forms left = 0;
} else {
left -= tag_length;
- tag = tag.Next;
}
}
@@ -295,15 +391,7 @@ namespace System.Windows.Forms streamline = true;
}
- // Delete empty orphaned tags at the end
LineTag walk = tag;
- while (walk != null && walk.Next != null && walk.Next.Length == 0) {
- LineTag t = walk;
- walk.Next = walk.Next.Next;
- if (walk.Next != null)
- walk.Next.Previous = t;
- walk = walk.Next;
- }
// Adjust the start point of any tags following
if (tag != null) {
@@ -314,6 +402,15 @@ namespace System.Windows.Forms }
}
+ // Delete empty orphaned tags at the end. Do this after adjusting their starts, otherwise we might delete tags that acutally do have content.
+ while (walk != null && walk.Next != null && walk.Next.Length == 0) {
+ LineTag t = walk;
+ walk.Next = walk.Next.Next;
+ if (walk.Next != null)
+ walk.Next.Previous = t;
+ walk = walk.Next;
+ }
+
recalc = true;
if (streamline)
@@ -361,7 +458,7 @@ namespace System.Windows.Forms pos = text.Length - 1;
while (tag != null) {
- if (((tag.Start - 1) <= pos) && (pos <= (tag.Start + tag.Length - 1)))
+ if (((tag.Start - 1) <= pos) && (pos < (tag.Start + tag.Length - 1)))
return LineTag.GetFinalTag (tag);
tag = tag.Next;
@@ -434,6 +531,33 @@ namespace System.Windows.Forms // Insert the text into the StringBuilder
text.Insert (pos, s);
+ // Check that tag is still in use in the line. If not, then we choose the last tag at that position.
+ LineTag t = tags;
+ while (t != null) {
+ if (((t.Start - 1) <= pos) && (pos < (t.End - 1) || (pos == t.End - 1 && t.Length == 0))) {
+ // found the location
+ bool foundTag = false;
+ while (pos < (t.Start + t.Length - 1)) {
+ if (t == tag) {
+ foundTag = true;
+ break;
+ }
+ if (t.Next == null)
+ break;
+ t = t.Next;
+ }
+ if (!foundTag) {
+ if (pos < (t.Start + t.Length - 1)) {
+ tag = t.Previous;
+ } else {
+ tag = t;
+ }
+ }
+ break;
+ }
+ t = t.Next;
+ }
+
// Update the start position of every tag after this one
tag = tag.Next;
@@ -455,55 +579,94 @@ namespace System.Windows.Forms /// </summary>
internal bool RecalculateLine (Graphics g, Document doc)
{
- return RecalculateLine (g, doc, kerning_fonts.ContainsKey (tags.Font.GetHashCode ()));
- }
-
- private bool RecalculateLine (Graphics g, Document doc, bool handleKerning)
- {
LineTag tag;
int pos;
int len;
+ Font currentFont;
+ int currentFontStart;
SizeF size;
float w;
int prev_offset;
bool retval;
bool wrapped;
+ bool first_in_para;
Line line;
int wrap_pos;
+ int prev_wrap_pos;
int prev_height;
int prev_ascent;
- float add_width;
+ float prev_spacing_before;
+ int max_above_baseline;
+ int max_below_baseline;
+ int total_ascent;
+ int total_descent;
+ TabStop lastTab;
+ int lastTabPos;
+ char c;
+ bool handleKerning;
+ float right_indent;
pos = 0;
len = this.text.Length;
+ currentFont = tags.FontToDisplay;
+ currentFontStart = 0;
tag = this.tags;
prev_offset = this.offset; // For drawing optimization calculations
prev_height = this.height;
prev_ascent = this.ascent;
+ prev_spacing_before = this.SpacingBefore;
+ max_above_baseline = 0;
+ max_below_baseline = 0;
+ total_ascent = 0;
+ total_descent = 0;
+ lastTab = null;
+ lastTabPos = 0;
this.height = 0; // Reset line height
this.ascent = 0; // Reset the ascent for the line
tag.Shift = 0; // Reset shift (which should be stored as pixels, not as points)
+ right_indent = Math.Max(this.right_indent, 0); // Ignore any negative right indent.
- if (ending == LineEnding.Wrap)
- widths[0] = document.left_margin + hanging_indent;
+ if (line_no > 0) {
+ line = doc.GetLine (LineNo - 1);
+ first_in_para = line != null && line.ending != LineEnding.Wrap;
+ } else {
+ first_in_para = true;
+ }
+
+ if (first_in_para)
+ widths [0] = indent;
else
- widths[0] = document.left_margin + indent;
+ widths [0] = indent + hanging_indent;
+
+ if (widths [0] < 0)
+ widths [0] = 0; // Don't allow a negative indent to take the line to a negative position.
+
+ widths [0] += document.left_margin;
this.recalc = false;
retval = false;
wrapped = false;
wrap_pos = 0;
- add_width = 0;
+ prev_wrap_pos = 0;
- while (pos < len) {
+ handleKerning = kerning_fonts.ContainsKey (currentFont.GetHashCode ());
+ while (pos < len) {
while (tag.Length == 0) { // We should always have tags after a tag.length==0 unless len==0
//tag.Ascent = 0;
- tag.Shift = (tag.Line.ascent - tag.Ascent) / 72;
+ tag.Shift = (tag.Line.ascent - tag.Ascent); // / 72;
tag = tag.Next;
+ if (tag.Length != 0 && tag.FontToDisplay != currentFont) {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
+ currentFont = tag.FontToDisplay;
+ currentFontStart = pos;
+ handleKerning = kerning_fonts.ContainsKey (currentFont.GetHashCode ());
+ }
}
+ c = text [pos];
+
// kerning is a problem. The original code in this method assumed that the
// width of a string equals the sum of the widths of its characters. This is
// not true when kerning takes place during the display process. Since it's
@@ -520,44 +683,103 @@ namespace System.Windows.Forms // MeasureText doesn't measure trailing spaces, so we do the best we can for those
// in the else branch.
// It doesn't measure /t characters either, we need to add it manually with add_width.
- size = TextBoxTextRenderer.MeasureText (g, text.ToString (0, pos + 1), tag.Font);
- newWidth = widths[0] + size.Width + add_width;
+ size = TextBoxTextRenderer.MeasureText (g, text.ToString (currentFontStart, pos + 1 - currentFontStart), currentFont);
+ newWidth = widths [currentFontStart] + size.Width;
}
- else
- {
+ else if (c != '\t') {
size = tag.SizeOfPosition (g, pos);
w = size.Width;
newWidth = widths[pos] + w;
- if (text[pos] == '\t') add_width += w;
+ } else {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
+ currentFontStart = pos + 1; // Don't try handling the tab along with kerned text.
+
+ if (lastTab != null) {
+ ProcessLastTab (lastTab, lastTabPos, pos);
+ lastTab = null;
+ }
+
+ float l = widths [pos];
+ w = -1;
+ for (int i = 0; i < tab_stops.Count; i++) {
+ if (tab_stops [i].Position > l) {
+ lastTab = tab_stops [i];
+ lastTabPos = pos;
+ w = lastTab.GetInitialWidth (this, pos);
+ break;
+ }
+ }
+
+ if (w < 0) {
+ w = tag.SizeOfPosition (g, pos).Width;
+ }
+
+ newWidth = widths [pos] + w;
}
- if (Char.IsWhiteSpace (text[pos]))
- wrap_pos = pos + 1;
-
- if (doc.wrap) {
- if ((wrap_pos > 0) && (wrap_pos != len) && (newWidth + 5) > (doc.viewport_width - this.right_indent)) {
- // Make sure to set the last width of the line before wrapping
- widths[pos + 1] = newWidth;
-
- pos = wrap_pos;
- len = text.Length;
- doc.Split (this, tag, pos);
- ending = LineEnding.Wrap;
- len = this.text.Length;
-
- retval = true;
- wrapped = true;
- } else if (pos > 1 && newWidth > (doc.viewport_width - this.right_indent)) {
- // No suitable wrap position was found so break right in the middle of a word
-
- // Make sure to set the last width of the line before wrapping
- widths[pos + 1] = newWidth;
-
- doc.Split (this, tag, pos);
- ending = LineEnding.Wrap;
- len = this.text.Length;
- retval = true;
- wrapped = true;
+ if (doc.Wrap) {
+ // FIXME: Technically there are multiple no-break spaces, not just the main one.
+ if ((Char.IsWhiteSpace (c) && c != '\u00A0') || c == '-' || c == '\u2013' || c == '\u2014') {
+ // Primarily break on dashes or whitespace other than a no-break space.
+ prev_wrap_pos = wrap_pos;
+ if (c == '\t') {
+ wrap_pos = pos; // Wrap before tabs for some reason.
+ } else {
+ wrap_pos = pos + 1;
+ }
+ }
+
+ if (newWidth > (doc.viewport_width - this.right_indent)) {
+ LineTag split_tag = null;
+ if (wrap_pos > 0) {
+ // Make sure to set the last width of the line before wrapping
+ widths [pos + 1] = newWidth;
+
+ if (Char.IsWhiteSpace (c)) {
+ if (wrap_pos > pos) {
+ while (wrap_pos < text.Length && Char.IsWhiteSpace (text [wrap_pos]) && text [wrap_pos] != '\t') {
+ wrap_pos++;
+ }
+ pos++;
+ wrapped = true;
+ // don't try pulling more into this line, but keep looping to deal with the rest of the widths and tags
+ }
+ } else {
+ if (wrap_pos > pos && pos > 0) {
+ // We're at a dash (otherwise we'd be above), but don't have room to fit it in.
+ // Wrap at the previous wrap point if possible.
+ wrap_pos = prev_wrap_pos > 0 ? prev_wrap_pos : pos;
+ }
+ split_tag = tag;
+ pos = wrap_pos;
+ }
+ } else if (pos > 0) {
+ // No suitable wrap position was found so break right in the middle of a word
+
+ // Make sure to set the last width of the line before wrapping
+ widths [pos + 1] = newWidth;
+
+ split_tag = tag;
+ } // Else don't wrap -- pos == 0, so we'd infinite loop adding blank lines before this.
+
+ if (split_tag != null) {
+ if (lastTab != null) {
+ ProcessLastTab (lastTab, lastTabPos, pos);
+ lastTab = null;
+ }
+
+ while (pos < split_tag.Start)
+ split_tag = split_tag.Previous;
+ // We have to pass Split the correct tag, and that can change if pos
+ // is set somewhere before the tag change (e.g. by wrap_pos).
+
+ doc.Split (this, split_tag, pos);
+ ending = LineEnding.Wrap;
+ len = this.text.Length;
+
+ retval = true;
+ wrapped = true;
+ }
}
}
@@ -569,12 +791,23 @@ namespace System.Windows.Forms if (pos == len) {
line = doc.GetLine (this.line_no + 1);
- if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None)) {
- // Pull the two lines together
- doc.Combine (this.line_no, this.line_no + 1);
- len = this.text.Length;
- retval = true;
- }
+ do {
+ if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None) &&
+ (widths[pos] < (doc.viewport_width - this.right_indent) || line.text.Length == 0)) {
+ // Pull the two lines together
+ // Only do this if the line isn't already full, or the next line is empty.
+ var h = this.height; // Back up h, because Combine sets it to zero.
+ doc.Combine (this, line);
+ this.height = h; // And restore it. There's no point starting at the start again.
+ // Document.Combine() called Line.Streamline(), so it is possible tag points a tag that got removed.
+ tag = FindTag (pos - 1); // So make sure we've got the correct tag.
+ len = this.text.Length;
+ line = doc.GetLine (this.line_no + 1);
+ retval = true;
+ }
+ } while ((ending == LineEnding.Wrap || ending == LineEnding.None) && line != null && line.text.Length == 0);
+ // If the next line is empty, do it again (if possible).
+ // The amount of room on this line doesn't matter when there's no text being added...
}
}
@@ -582,54 +815,63 @@ namespace System.Windows.Forms // We just found the end of our current tag
tag.Height = tag.MaxHeight ();
- // Check if we're the tallest on the line (so far)
- if (tag.Height > this.height)
- this.height = tag.Height; // Yep; make sure the line knows
-
- if (tag.Ascent > this.ascent) {
- LineTag t;
-
- // We have a tag that has a taller ascent than the line;
- t = tags;
+ /* line.ascent is the highest point above the baseline.
+ * total_ascent will equal the maximum distance of the tag above the baseline.
+ * total_descent is needed to calculate the line height.
+ * tag.Shift does not include tag.CharOffset, because Shift puts the tag
+ * on the baseline, while CharOffset moves the baseline.
+ * However, we move the normal baseline when CharOffset is trying to push
+ * stuff off the top.
+ */
+ total_ascent = tag.Ascent + (int)tag.CharOffset;
+ total_descent = tag.Descent - (int)tag.CharOffset; // gets bigger as CharOffset gets smaller
+ if (total_ascent > max_above_baseline) {
+ int moveBy = total_ascent - max_above_baseline;
+ max_above_baseline = total_ascent;
+
+ LineTag t = tags;
while (t != null && t != tag) {
- t.Shift = (tag.Ascent - t.Ascent) / 72;
+ t.Shift += moveBy;
t = t.Next;
}
- // Save on our line
- this.ascent = tag.Ascent;
+ tag.Shift = (int)tag.CharOffset;
+ this.ascent = max_above_baseline;
} else {
- tag.Shift = (this.ascent - tag.Ascent) / 72;
+ tag.Shift = (this.ascent - tag.Ascent);
}
+ if (total_descent > max_below_baseline)
+ max_below_baseline = total_descent;
+
+ if (this.height < max_above_baseline + max_below_baseline + tag.Height - tag.Ascent - tag.Descent)
+ this.height = max_above_baseline + max_below_baseline + tag.Height - tag.Ascent - tag.Descent;
+
tag = tag.Next;
if (tag != null) {
+ if (tag.Length != 0 && tag.FontToDisplay != currentFont) {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
+ currentFont = tag.FontToDisplay;
+ currentFontStart = pos;
+ handleKerning = kerning_fonts.ContainsKey (currentFont.GetHashCode ());
+ }
tag.Shift = 0;
- wrap_pos = pos;
+ // We can't just wrap on tag boundaries -- e.g. if the first letter of the word has a different colour / font.
}
}
}
- var fullText = text.ToString();
- if (!handleKerning && fullText.Length > 1 && !wrapped)
- {
- // Check whether kerning takes place for this string and font.
- var realSize = TextBoxTextRenderer.MeasureText(g, fullText, tags.Font);
- float realWidth = realSize.Width + widths[0];
- // MeasureText ignores trailing whitespace, so we will too at this point.
- int length = fullText.TrimEnd().Length;
- float sumWidth = widths[length];
- if (realWidth != sumWidth)
- {
- kerning_fonts.Add(tags.Font.GetHashCode (), true);
- // Using a slightly incorrect width this time around isn't that bad. All that happens
- // is that the cursor is a pixel or two off until the next character is typed. It's
- // the accumulation of pixel after pixel that causes display problems.
- }
+ if (pos != currentFontStart) {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
}
- while (tag != null) {
- tag.Shift = (tag.Line.ascent - tag.Ascent) / 72;
+ if (lastTab != null) {
+ ProcessLastTab (lastTab, lastTabPos, pos);
+ lastTab = null;
+ }
+
+ while (tag != null) {
+ tag.Shift = (tag.Line.ascent - tag.Ascent); // / 72;
tag = tag.Next;
}
@@ -639,12 +881,49 @@ namespace System.Windows.Forms tags.Shift = 0;
}
- if (prev_offset != offset || prev_height != this.height || prev_ascent != this.ascent)
+ this.textHeight = this.height;
+ this.height = (int)(this.LineSpacing + this.TotalParagraphSpacing);
+
+ if (prev_offset != offset || prev_height != this.height || prev_ascent != this.ascent ||
+ Math.Abs (prev_spacing_before - this.SpacingBefore) > document.Dpi / 1440f)
retval = true;
return retval;
}
+ private void ProcessLastTab (TabStop tab, int tab_pos, int pos)
+ {
+ float prevTabRight = widths[tab_pos + 1];
+ float tabRight = tab.CalculateRight (this, tab_pos);
+ float change = tabRight - prevTabRight;
+
+ for (int i = tab_pos + 1; i <= pos; i++) {
+ widths[i] += change;
+ }
+ }
+
+ private void CheckKerning (Graphics g, Font font, int start, int length)
+ {
+ if (length > 1) {
+ if (!kerning_fonts.ContainsKey (font.GetHashCode ())) {
+ // Check whether kerning takes place for this string and font.
+ var partText = text.ToString(start, length);
+ var realSize = TextBoxTextRenderer.MeasureText(g, partText, font);
+ float realWidth = realSize.Width + widths[start + 1];
+ // MeasureText ignores trailing whitespace, so we will too at this point.
+ int textLength = partText.TrimEnd().Length;
+ float sumWidth = widths[textLength + start + 1];
+ if (realWidth != sumWidth)
+ {
+ kerning_fonts.Add(font.GetHashCode (), true);
+ // Using a slightly incorrect width this time around isn't that bad. All that happens
+ // is that the cursor is a pixel or two off until the next character is typed. It's
+ // the accumulation of pixel after pixel that causes display problems.
+ }
+ }
+ }
+ }
+
/// <summary>
/// Recalculate a single line using the same char for every character in the line
/// </summary>
@@ -667,13 +946,14 @@ namespace System.Windows.Forms w = TextBoxTextRenderer.MeasureText (g, doc.password_char, tags.Font).Width;
- if (this.height != (int)tag.Font.Height)
+ if (this.textHeight != (int)tag.Font.Height)
ret = true;
else
ret = false;
- this.height = (int)tag.Font.Height;
- tag.Height = this.height;
+ this.textHeight = (int)tag.Font.Height;
+ tag.Height = this.textHeight;
+ this.height = (int)(this.textHeight + this.LineSpacing + this.TotalParagraphSpacing);
this.ascent = tag.Ascent;
@@ -684,7 +964,42 @@ namespace System.Windows.Forms return ret;
}
-
+
+ internal void CalculateAlignment ()
+ {
+ var alignmentWidth = document.ViewPortWidth - document.left_margin - document.right_margin;
+ var alignmentLineWidth = GetAlignmentLineWidth ();
+
+ switch (alignment) {
+ case HorizontalAlignment.Left:
+ align_shift = 0;
+ break;
+ case HorizontalAlignment.Center:
+ align_shift = (alignmentWidth - alignmentLineWidth) / 2;
+ break;
+ case HorizontalAlignment.Right:
+ align_shift = alignmentWidth - alignmentLineWidth;
+ break;
+ }
+
+ align_shift = Math.Max (align_shift, 0); // Don't allow negative shifts.
+ }
+
+ private int GetAlignmentLineWidth ()
+ {
+ int last = text.Length - 1;
+ if (last < 0)
+ return 0;
+
+ char c = text [last];
+ while (last > 0 && Char.IsWhiteSpace (c) && c != '\t' && c != '\u00A0') {
+ c = text [--last];
+ }
+ // widths[0] has both the left margin and the left indents.
+ // Remove the margin (it is part of the viewport) and add the right indents (part of the line width, for alignment purposes).
+ return (int)(widths [last + 1] - document.left_margin + Math.Max (right_indent, 0));
+ }
+
internal void Streamline (int lines)
{
LineTag current;
@@ -711,7 +1026,7 @@ namespace System.Windows.Forms return;
while (next != null) {
- // Take out 0 length tags unless it's the last tag in the document
+ // Take out 0 length tags unless it's the last tag in the document.
if (current.IsTextTag && next.Length == 0 && next.IsTextTag) {
if ((next.Next != null) || (line_no != lines)) {
current.Next = next.Next;
diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs index a551e813de9..38e5bb58dd5 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs @@ -21,6 +21,7 @@ //
// Authors:
// Peter Bartok pbartok@novell.com
+// Karl Scowen <contact@scowencomputers.co.nz>
//
//
@@ -44,6 +45,10 @@ namespace System.Windows.Forms private string link_text; // The full link text e.g. this might be
// word-wrapped to "w" but this would be
// "www.example.com"
+ private bool visible;
+ private TextPositioning text_position; // Normal / superscript / subscript
+ private Font small_font; // Cached font for superscript / subscript
+ private float char_offset; // Shift the text baseline up or down
// Payload; text
private int start; // start, in chars; index into Line.text
@@ -53,7 +58,8 @@ namespace System.Windows.Forms private int height; // Height in pixels of the text this tag describes
private int ascent; // Ascent of the font for this tag
private int descent; // Descent of the font for this tag
- private int shift; // Shift down for this tag, to stay on baseline
+ private int shift; // Shift down for this tag, to stay on baseline.
+ // Measured from top of line to top of tag.
// Administrative
private Line line; // The line we're on
@@ -69,6 +75,7 @@ namespace System.Windows.Forms link_font = null;
is_link = false;
link_text = null;
+ visible = true;
}
#endregion // Constructors
@@ -113,6 +120,16 @@ namespace System.Windows.Forms return link_font;
}
+ if (TextPosition != TextPositioning.Normal) {
+ if (small_font == null)
+ small_font = new Font (font.FontFamily, font.Size * 0.583F, font.Style);
+
+ if (IsLink)
+ return new Font (small_font, font.Style | FontStyle.Underline);
+ else
+ return small_font;
+ }
+
return font;
}
}
@@ -122,20 +139,43 @@ namespace System.Windows.Forms set {
if (font != value) {
link_font = null;
+ small_font = null;
font = value;
height = Font.Height;
XplatUI.GetFontMetrics (Hwnd.GraphicsContext, Font, out ascent, out descent);
+ float scale_factor = font.GetHeight () / font.FontFamily.GetLineSpacing (font.Style);
+ ascent = (int) Math.Ceiling (ascent * scale_factor);
+ descent = (int) Math.Ceiling (descent * scale_factor);
line.recalc = true;
}
}
}
+ public TextPositioning TextPosition {
+ get { return text_position; }
+ set { text_position = value; }
+ }
+
+ public float CharOffset {
+ get { return char_offset; }
+ set { char_offset = value; }
+ }
+
public int Height {
get { return height; }
set { height = value; }
}
+ public int DrawnHeight {
+ get {
+ if (text_position != TextPositioning.Normal)
+ return (int) (height * 0.583F);
+
+ return height;
+ }
+ }
+
public virtual bool IsTextTag {
get { return true; }
}
@@ -186,7 +226,7 @@ namespace System.Windows.Forms throw new Exception("New tag makes an insane tag");
}
#endif
- start = value;
+ start = value;
}
}
@@ -206,9 +246,14 @@ namespace System.Windows.Forms }
}
+ public bool Visible {
+ get { return visible; }
+ set { visible = value; }
+ }
+
public float Width {
get {
- if (Length == 0)
+ if (Length == 0 || !visible)
return 0;
return line.widths [start + Length - 1] - (start != 0 ? line.widths [start - 1] : 0);
}
@@ -222,6 +267,15 @@ namespace System.Windows.Forms }
}
+ public int OffsetY {
+ get {
+ if (text_position == TextPositioning.Subscript)
+ return (int) (height * 0.45F);
+
+ return 0;
+ }
+ }
+
public bool IsLink {
get { return is_link; }
set { is_link = value; }
@@ -253,8 +307,8 @@ namespace System.Windows.Forms new_tag = new LineTag(line, pos);
new_tag.CopyFormattingFrom (this);
- new_tag.next = this.next;
- this.next = new_tag;
+ new_tag.Next = this.next;
+ this.Next = new_tag;
new_tag.previous = this;
if (new_tag.next != null)
@@ -269,7 +323,7 @@ namespace System.Windows.Forms if (!this.Equals (other))
return false;
- this.next = other.next;
+ this.Next = other.next;
if (this.next != null)
this.next.previous = this;
@@ -282,6 +336,9 @@ namespace System.Windows.Forms Font = other.font;
color = other.color;
back_color = other.back_color;
+ TextPosition = other.text_position;
+ CharOffset = other.CharOffset;
+ Visible = other.Visible;
}
public void Delete ()
@@ -312,6 +369,8 @@ namespace System.Windows.Forms public virtual void Draw (Graphics dc, Color color, float x, float y, int start, int end)
{
+ if (text_position == TextPositioning.Subscript)
+ y += OffsetY;
TextBoxTextRenderer.DrawText (dc, line.text.ToString (start, end).Replace ("\r", string.Empty), FontToDisplay, color, x, y, false);
}
@@ -328,6 +387,14 @@ namespace System.Windows.Forms public virtual void Draw (Graphics dc, Color color, float xoff, float y, int drawStart, int drawEnd,
string text, out Rectangle measuredText, bool measureText)
{
+ if (!visible) {
+ measuredText = new Rectangle ();
+ return;
+ }
+
+ if (text_position == TextPositioning.Subscript)
+ y += OffsetY;
+
if (measureText) {
int xstart = (int)line.widths [drawStart] + (int)xoff;
int xend = (int)line.widths [drawEnd] - (int)line.widths [drawStart];
@@ -342,7 +409,7 @@ namespace System.Windows.Forms while (drawStart < drawEnd) {
int tab_index = text.IndexOf ("\t", drawStart);
- if (tab_index == -1)
+ if (tab_index == -1 || tab_index > drawEnd)
tab_index = drawEnd;
TextBoxTextRenderer.DrawText (dc, text.Substring (drawStart, tab_index - drawStart).Replace ("\r", string.Empty), FontToDisplay, color, xoff + line.widths [drawStart], y, false);
@@ -380,7 +447,16 @@ namespace System.Windows.Forms if (this.LinkText != other.LinkText)
return false;
- if (this.font.Equals (other.font) && this.color.Equals (other.color))
+ if (this.TextPosition != other.TextPosition)
+ return false;
+
+ if (this.CharOffset != other.CharOffset)
+ return false;
+
+ if (this.Visible != other.Visible)
+ return false;
+
+ if (this.font.Equals (other.font) && this.color.Equals (other.color) && this.back_color.Equals (other.back_color))
return true;
return false;
@@ -409,11 +485,17 @@ namespace System.Windows.Forms return null;
}
+ public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor, FormatSpecified specified)
+ {
+ return FormatText (line, formatStart, length, font, color, backColor, TextPositioning.Normal, 0, true, specified);
+ }
+
/// <summary>Applies 'font' and 'brush' to characters starting at 'start' for 'length' chars;
/// Removes any previous tags overlapping the same area;
/// returns true if lineheight has changed</summary>
/// <param name="formatStart">1-based character position on line</param>
- public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor, FormatSpecified specified)
+ public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor,
+ TextPositioning text_position, float char_offset, bool visible, FormatSpecified specified)
{
LineTag tag;
LineTag start_tag;
@@ -422,7 +504,7 @@ namespace System.Windows.Forms bool retval = false; // Assume line-height doesn't change
// Too simple?
- if (((FormatSpecified.Font & specified) == FormatSpecified.Font) && font.Height != line.height)
+ if (((FormatSpecified.Font & specified) == FormatSpecified.Font) && font.Height != line.TextHeight)
retval = true;
line.recalc = true; // This forces recalculation of the line in RecalculateDocument
@@ -436,7 +518,7 @@ namespace System.Windows.Forms // Common special case
if ((formatStart == 1) && (length == tag.Length)) {
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -444,7 +526,7 @@ namespace System.Windows.Forms // we only need one new tag
if (formatStart == 1 && length == 0) {
line.tags.Break (1);
- SetFormat (line.tags, font, color, backColor, specified);
+ SetFormat (line.tags, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -455,7 +537,7 @@ namespace System.Windows.Forms // Find Tag will return tag 0 at position 3, but we should just
// use the empty tag after..
if (start_tag.End == formatStart && length == 0 && start_tag.Next != null && start_tag.Next.Length == 0) {
- SetFormat (start_tag.Next, font, color, backColor, specified);
+ SetFormat (start_tag.Next, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -463,13 +545,22 @@ namespace System.Windows.Forms while (start_tag.End == formatStart && start_tag.Next != null)
start_tag = start_tag.Next;
- tag = start_tag.Break (formatStart);
+ if (start_tag.Start == formatStart && start_tag.Length == length) {
+ SetFormat (start_tag, font, color, backColor, text_position, char_offset, visible, specified);
+ return retval;
+ }
+
+ // Break the tag if needed -- we don't need to break for the start if we're starting at its start.
+ if (start_tag.Start != formatStart)
+ tag = start_tag.Break (formatStart);
+ else
+ tag = start_tag;
// empty selection style at end of line - its the only situation
// where the rest of the tag would be empty, since we moved to the
// begining of next non empty tag
if (tag.Length == 0) {
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -477,25 +568,27 @@ namespace System.Windows.Forms // after our new (now) empty one..
if (length == 0) {
tag.Break (formatStart);
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
+ bool atEnd = false;
while (tag != null && tag.End <= end) {
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
+ atEnd |= tag.End == end;
tag = tag.next;
}
// did the last tag conveniently fit?
- if (tag != null && tag.End == end)
+ if (atEnd || (tag != null && tag.End == end))
return retval;
- /// Now do the last tag
+ // Now do the last tag
end_tag = FindTag (line, end-1);
if (end_tag != null) {
end_tag.Break (end);
- SetFormat (end_tag, font, color, backColor, specified);
+ SetFormat (end_tag, font, color, backColor, text_position, char_offset, visible, specified);
}
return retval;
@@ -509,6 +602,7 @@ namespace System.Windows.Forms int low = start;
int high = low + Length;
int length_no_ending = line.TextLengthWithoutEnding ();
+ float char_mid;
if (Length == 0)
return low-1;
@@ -517,7 +611,8 @@ namespace System.Windows.Forms return 0;
if (x < line.widths [low]) {
- if (low == 1 && x > (line.widths [1] / 2))
+ char_mid = (line.widths [1] + line.widths [0]) / 2;
+ if (low == 1 && x >= char_mid)
return low;
return low - 1;
}
@@ -535,9 +630,9 @@ namespace System.Windows.Forms high = mid;
}
- float char_width = line.widths[high] - line.widths[low];
+ char_mid = (line.widths [high] + line.widths [low]) / 2;
- if ((x - line.widths[low]) >= (char_width / 2))
+ if (x >= char_mid)
return high;
else
return low;
@@ -569,6 +664,12 @@ namespace System.Windows.Forms private static void SetFormat (LineTag tag, Font font, Color color, Color back_color, FormatSpecified specified)
{
+ SetFormat (tag, font, color, back_color, TextPositioning.Normal, 0, true, specified);
+ }
+
+ private static void SetFormat (LineTag tag, Font font, Color color, Color back_color, TextPositioning text_position,
+ float char_offset, bool visible, FormatSpecified specified)
+ {
if ((FormatSpecified.Font & specified) == FormatSpecified.Font) {
tag.Font = font;
}
@@ -577,28 +678,52 @@ namespace System.Windows.Forms if ((FormatSpecified.BackColor & specified) == FormatSpecified.BackColor) {
tag.back_color = back_color;
}
+ if ((FormatSpecified.TextPosition & specified) == FormatSpecified.TextPosition)
+ tag.TextPosition = text_position;
+ if ((FormatSpecified.CharOffset & specified) == FormatSpecified.CharOffset)
+ tag.CharOffset = char_offset;
+ if ((FormatSpecified.Visibility & specified) == FormatSpecified.Visibility)
+ tag.Visible = visible;
// Console.WriteLine ("setting format: {0} {1} new color {2}", color.Color, specified, tag.color.Color);
}
public virtual SizeF SizeOfPosition (Graphics dc, int pos)
{
- if (pos >= line.TextLengthWithoutEnding () && line.document.multiline)
+ if ((pos >= line.TextLengthWithoutEnding () && line.document.multiline) || !visible)
return SizeF.Empty;
string text = line.text.ToString (pos, 1);
- switch ((int) text [0]) {
+ switch ((int)text [0]) {
case '\t':
if (!line.document.multiline)
goto case 10;
- SizeF res = TextBoxTextRenderer.MeasureText (dc, " ", font);
- res.Width *= 8.0F;
+ SizeF res = TextBoxTextRenderer.MeasureText (dc, " ", FontToDisplay); // This way we get the height, not that it is ever used...
+ float left = line.widths [pos];
+ float right = -1;
+ TabStopCollection stops = line.tab_stops;
+ float tabPos;
+ for (int i = 0; i < stops.Count; i++) {
+ tabPos = stops [i].Position;
+ if (tabPos >= left) {
+ if (tabPos <= line.document.viewport_width - line.RightIndent)
+ break; // Can't use tabs that are past the end of the line.
+
+ right = stops [i].CalculateRight (line, pos);
+ break;
+ }
+ }
+ if (right < 0) {
+ float maxWidth = dc.DpiX / 2; // tab stops are 1/2"
+ right = (float)(Math.Floor (left / maxWidth) + 1) * maxWidth;
+ }
+ res.Width = right - left;
return res;
case 10:
case 13:
- return TextBoxTextRenderer.MeasureText (dc, "\u000D", font);
+ return TextBoxTextRenderer.MeasureText (dc, "\u000D", FontToDisplay);
}
-
- return TextBoxTextRenderer.MeasureText (dc, text, font);
+
+ return TextBoxTextRenderer.MeasureText (dc, text, FontToDisplay);
}
public virtual string Text ()
diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs index fbc74eed38d..b513cf90910 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ListBox.cs @@ -1614,7 +1614,7 @@ namespace System.Windows.Forms private bool KeySearch (Keys key) { char c = (char) key; - if (!Char.IsLetterOrDigit (c)) + if (!Char.IsLetterOrDigit (c) || SelectionMode == SelectionMode.None) return false; int idx = FindString (c.ToString (), SelectedIndex); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs index 9073f2c10c4..1b5f9513a23 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok <pbartok@novell.com> +// Karl Scowen <contact@scowencomputers.co.nz> // // @@ -28,6 +29,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; @@ -55,7 +57,9 @@ namespace System.Windows.Forms { // properties so we can revert private Stack rtf_section_stack; - private RTF.TextMap rtf_text_map; + bool fire_contents_resized; + Size existing_contents_size; + private int rtf_skip_count; private int rtf_cursor_x; private int rtf_cursor_y; @@ -64,7 +68,7 @@ namespace System.Windows.Forms { private bool enable_auto_drag_drop; private RichTextBoxLanguageOptions language_option; private bool rich_text_shortcuts_enabled; - private Color selection_back_color; + #endregion // Local Variables #region Public Constructors @@ -85,15 +89,17 @@ namespace System.Windows.Forms { rtf_style = new RtfSectionStyle (); rtf_section_stack = null; + fire_contents_resized = true; + scrollbars = RichTextBoxScrollBars.Both; alignment = HorizontalAlignment.Left; + document.SizeChanged += new EventHandler<Document.SizeChangedEventArgs> (ContentSizeChanged); LostFocus += new EventHandler(RichTextBox_LostFocus); GotFocus += new EventHandler(RichTextBox_GotFocus); BackColor = ThemeEngine.Current.ColorWindow; backcolor_set = false; language_option = RichTextBoxLanguageOptions.AutoFontSizeAdjust; rich_text_shortcuts_enabled = true; - selection_back_color = DefaultBackColor; ForeColor = ThemeEngine.Current.ColorWindowText; base.HScrolled += new EventHandler(RichTextBox_HScrolled); @@ -133,6 +139,29 @@ namespace System.Windows.Forms { private void RichTextBox_GotFocus(object sender, EventArgs e) { Invalidate(); } + + private void ContentSizeChanged (object sender, Document.SizeChangedEventArgs e) + { + ContentSizeChanged (); + } + + private void ContentSizeChanged () + { + if (fire_contents_resized && (existing_contents_size.IsEmpty || + existing_contents_size.Height != document.Height || existing_contents_size.Width != document.Width)) { + int width; + int height = document.Height + document.top_margin * 2 + Height - ClientRectangle.Height; + + if (Multiline) { + width = Width; // yes, this is the insanity that is the traditional .Net implementation... + } else { + width = document.Width + document.left_margin + document.right_margin + Width - ClientRectangle.Width; + } + + ContentsResizedEventArgs args = new ContentsResizedEventArgs (new Rectangle (Left, Top, width, height)); + OnContentsResized (args); + } + } #endregion // Private & Internal Methods #region Public Instance Properties @@ -324,14 +353,25 @@ namespace System.Windows.Forms { set { MemoryStream data; + fire_contents_resized = false; + existing_contents_size = new Size (document.Width, document.Height); + document.Empty(); data = new MemoryStream(Encoding.ASCII.GetBytes(value), false); InsertRTFFromStream(data, 0, 1); + Line line = document.GetLine (1); + document.SetSelection (line, 0); + document.PositionCaret (line, 0); + data.Close(); Invalidate(); + + fire_contents_resized = true; + ContentSizeChanged (); + existing_contents_size = Size.Empty; } } @@ -371,6 +411,9 @@ namespace System.Windows.Forms { Line line; LineTag tag; + fire_contents_resized = false; + existing_contents_size = new Size (document.Width, document.Height); + document.SuspendRecalc (); if (document.selection_visible) { document.ReplaceSelection("", false); } @@ -393,14 +436,19 @@ namespace System.Windows.Forms { int nl_length = document.LineEndingLength (XplatUI.RunningOnUnix ? LineEnding.Rich : LineEnding.Hard); document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * nl_length, out line, out tag, out sel_start); - if (sel_start >= line.text.Length) - sel_start = line.text.Length -1; + if (sel_start > line.text.Length) + sel_start = line.text.Length; //zero-based, but we want to go after the last character rather than before. document.SetSelection(line, sel_start); document.PositionCaret(line, sel_start); + document.ResumeRecalc(true); document.DisplayCaret(); ScrollToCaret(); OnTextChanged(EventArgs.Empty); + + fire_contents_resized = true; + ContentSizeChanged(); + existing_contents_size = Size.Empty; } } @@ -473,12 +521,56 @@ namespace System.Windows.Forms { } } - [MonoTODO ("Stub, does nothing")] [Browsable (false)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public Color SelectionBackColor { - get { return selection_back_color; } - set { selection_back_color = value; } + get { + Color back_colour; + LineTag start; + LineTag end; + LineTag tag; + + start = document.selection_start.line.FindTag (document.selection_start.pos); + + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); + } else { + end = start; + } + + back_colour = start.BackColor; + + tag = start; + while (tag != null) { + if (back_colour != tag.BackColor) + return Color.Empty; + + if (tag == end) + break; + + tag = document.NextTag (tag); + } + + return back_colour; + } + set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex (document.selection_end.line, document.selection_end.pos); + + document.FormatText (document.selection_start.line, document.selection_start.pos + 1, + document.selection_end.line, document.selection_end.pos + 1, null, + Color.Empty, value, FormatSpecified.BackColor); + + document.CharIndexToLineTag (sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag (sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView (document.selection_start.line, 0); + //Re-Align the caret in case its changed size or position + Document.AlignCaret (false); + } } [Browsable(false)] @@ -497,13 +589,54 @@ namespace System.Windows.Forms { [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionCharOffset { get { - return 0; + float char_offset; + LineTag start; + LineTag end; + LineTag tag; + + start = document.selection_start.line.FindTag (document.selection_start.pos); + + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); + } else { + end = start; + } + + char_offset = start.CharOffset; + + tag = start; + while (tag != null) { + if (Math.Abs(char_offset - tag.CharOffset) > 0.01) + return 0; + + if (tag == end) + break; + + tag = document.NextTag (tag); + } + + return (int)char_offset; } set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex (document.selection_end.line, document.selection_end.pos); + + document.FormatText (document.selection_start.line, document.selection_start.pos + 1, + document.selection_end.line, document.selection_end.pos + 1, null, + Color.Empty, Color.Empty, TextPositioning.Normal, value, true, FormatSpecified.CharOffset); + + document.CharIndexToLineTag (sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag (sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView (document.selection_start.line, 0); + //Re-Align the caret in case its changed size or position -- probably not necessary + Document.AlignCaret (false); } } @@ -516,11 +649,11 @@ namespace System.Windows.Forms { LineTag end; LineTag tag; - if (selection_length > 0) { - start = document.selection_start.line.FindTag (document.selection_start.pos + 1); - end = document.selection_start.line.FindTag (document.selection_end.pos); + start = document.selection_start.line.FindTag (document.selection_start.pos); + + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); } else { - start = document.selection_start.line.FindTag (document.selection_start.pos); end = start; } @@ -575,17 +708,16 @@ namespace System.Windows.Forms { LineTag end; LineTag tag; - if (selection_length > 0) { - start = document.selection_start.line.FindTag (document.selection_start.pos + 1); - end = document.selection_start.line.FindTag (document.selection_end.pos); + start = document.selection_start.line.FindTag (document.selection_start.pos); + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); } else { - start = document.selection_start.line.FindTag (document.selection_start.pos); end = start; } font = start.Font; - if (selection_length > 1) { + if (SelectionLength > 1) { tag = start; while (tag != null) { @@ -626,26 +758,106 @@ namespace System.Windows.Forms { [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionHangingIndent { get { - return 0; + int indent; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + indent = (int)start.hanging_indent; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if ((int)line.hanging_indent != indent) { + return 0; + } + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + + return indent; } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.HangingIndent = value; + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionIndent { get { - return 0; + int indent; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + indent = (int)start.indent; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if ((int)line.indent != indent) { + return 0; + } + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + + return indent; } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.Indent = value; + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } @@ -677,25 +889,105 @@ namespace System.Windows.Forms { [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionRightIndent { get { - return 0; + int indent; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + indent = (int)start.right_indent; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if ((int)line.right_indent != indent) { + return 0; + } + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + + return indent; } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.RightIndent = value; + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int[] SelectionTabs { get { - return new int[0]; + TabStopCollection tabs; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + tabs = start.TabStops; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if (!line.TabStops.Equals (tabs)) + return new int[0]; + + if (line == end) + break; + line = document.GetLine (line.line_no + 1); + } + + return tabs.ToPosArray (); } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.TabStops.Clear (); + foreach (int val in value) + line.TabStops.Add (new LeftTabStop (val)); + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } @@ -1308,26 +1600,47 @@ namespace System.Windows.Forms { private class RtfSectionStyle : ICloneable { internal Color rtf_color; + internal Color rtf_back_color; internal RTF.Font rtf_rtffont; - internal int rtf_rtffont_size; + internal float rtf_rtffont_size; internal FontStyle rtf_rtfstyle; - internal HorizontalAlignment rtf_rtfalign; - internal int rtf_par_line_left_indent; + internal HorizontalAlignment rtf_par_align; + internal float rtf_par_line_left_indent; + internal float rtf_par_first_line_indent; + internal float rtf_par_line_right_indent; internal bool rtf_visible; internal int rtf_skip_width; + internal float rtf_par_spacing_after; + internal float rtf_par_spacing_before; + internal float rtf_par_line_spacing; + internal bool rtf_par_line_spacing_multiple; + internal TextPositioning rtf_text_position; + internal float rtf_char_offset; + internal TabStop rtf_par_next_tab_stop = null; + internal TabStopCollection rtf_par_tab_stops = new TabStopCollection (); public object Clone () { RtfSectionStyle new_style = new RtfSectionStyle (); new_style.rtf_color = rtf_color; + new_style.rtf_back_color = rtf_back_color; new_style.rtf_par_line_left_indent = rtf_par_line_left_indent; - new_style.rtf_rtfalign = rtf_rtfalign; + new_style.rtf_par_first_line_indent = rtf_par_first_line_indent; + new_style.rtf_par_line_right_indent = rtf_par_line_right_indent; + new_style.rtf_par_align = rtf_par_align; new_style.rtf_rtffont = rtf_rtffont; new_style.rtf_rtffont_size = rtf_rtffont_size; new_style.rtf_rtfstyle = rtf_rtfstyle; new_style.rtf_visible = rtf_visible; new_style.rtf_skip_width = rtf_skip_width; + new_style.rtf_par_spacing_after = rtf_par_spacing_after; + new_style.rtf_par_spacing_before = rtf_par_spacing_before; + new_style.rtf_par_line_spacing = rtf_par_line_spacing; + new_style.rtf_par_line_spacing_multiple = rtf_par_line_spacing_multiple; + new_style.rtf_text_position = rtf_text_position; + new_style.rtf_char_offset = rtf_char_offset; + new_style.rtf_par_tab_stops = rtf_par_tab_stops.Clone (); return new_style; } @@ -1385,11 +1698,9 @@ namespace System.Windows.Forms { case RTF.Major.PictAttr: if (rtf.Picture != null && rtf.Picture.IsValid ()) { + FlushText (rtf, false, true); Line line = document.GetLine (rtf_cursor_y); - document.InsertPicture (line, 0, rtf.Picture); - rtf_cursor_x++; - - FlushText (rtf, true); + document.InsertPicture (line, rtf_cursor_x++, rtf.Picture); rtf.Picture = null; } break; @@ -1399,14 +1710,31 @@ namespace System.Windows.Forms { case RTF.Minor.ForeColor: { System.Windows.Forms.RTF.Color color; + color = System.Windows.Forms.RTF.Color.GetColor (rtf, rtf.Param); + + if (color != null) { + FlushText (rtf, false); + if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { + this.rtf_style.rtf_color = ForeColor; + } else { + this.rtf_style.rtf_color = Color.FromArgb (color.Red, color.Green, color.Blue); + } + FlushText (rtf, false); + } + break; + } + + case RTF.Minor.BackColor: { + System.Windows.Forms.RTF.Color color; + color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param); - + if (color != null) { FlushText(rtf, false); if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { - this.rtf_style.rtf_color = ForeColor; + this.rtf_style.rtf_back_color = BackColor; } else { - this.rtf_style.rtf_color = Color.FromArgb(color.Red, color.Green, color.Blue); + this.rtf_style.rtf_back_color = Color.FromArgb(color.Red, color.Green, color.Blue); } FlushText (rtf, false); } @@ -1415,7 +1743,7 @@ namespace System.Windows.Forms { case RTF.Minor.FontSize: { FlushText(rtf, false); - this.rtf_style.rtf_rtffont_size = rtf.Param / 2; + this.rtf_style.rtf_rtffont_size = rtf.Param / 2f; break; } @@ -1478,7 +1806,7 @@ namespace System.Windows.Forms { case RTF.Minor.Invisible: { FlushText (rtf, false); - rtf_style.rtf_visible = false; + rtf_style.rtf_visible = (rtf.Param != RTF.RTF.NoParam); break; } @@ -1487,6 +1815,36 @@ namespace System.Windows.Forms { rtf_style.rtf_rtfstyle &= ~FontStyle.Underline; break; } + + case RTF.Minor.SuperScrShrink: { + FlushText (rtf, false); + rtf_style.rtf_text_position = TextPositioning.Superscript; + break; + } + + case RTF.Minor.SubScrShrink: { + FlushText (rtf, false); + rtf_style.rtf_text_position = TextPositioning.Subscript; + break; + } + + case RTF.Minor.NoSuperSub: { + FlushText (rtf, false); + rtf_style.rtf_text_position = TextPositioning.Normal; + break; + } + + case RTF.Minor.SuperScript: { + FlushText (rtf, false); + rtf_style.rtf_char_offset = ((float) rtf.Param / 144.0F) * document.Dpi; + break; + } + + case RTF.Minor.SubScript: { + FlushText (rtf, false); + rtf_style.rtf_char_offset = -((float) rtf.Param / 144.0F) * document.Dpi; + break; + } } break; } @@ -1497,32 +1855,90 @@ namespace System.Windows.Forms { case RTF.Minor.ParDef: FlushText (rtf, false); rtf_style.rtf_par_line_left_indent = 0; - rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_par_first_line_indent = 0; + rtf_style.rtf_par_line_right_indent = 0; + rtf_style.rtf_par_spacing_after = 0; + rtf_style.rtf_par_spacing_before = 0; + rtf_style.rtf_par_line_spacing = 0; + rtf_style.rtf_par_line_spacing_multiple = false; + rtf_style.rtf_par_align = HorizontalAlignment.Left; + rtf_style.rtf_par_next_tab_stop = null; + rtf_style.rtf_par_tab_stops.Clear (); + break; + + case RTF.Minor.TabLeft: + rtf_style.rtf_par_next_tab_stop = new LeftTabStop (); + break; + + case RTF.Minor.TabCenter: + rtf_style.rtf_par_next_tab_stop = new CentredTabStop (); + break; + + case RTF.Minor.TabRight: + rtf_style.rtf_par_next_tab_stop = new RightTabStop (); + break; + + case RTF.Minor.TabDecimal: + rtf_style.rtf_par_next_tab_stop = new DecimalTabStop (); + break; + + case RTF.Minor.TabPos: + float tabPos = ((float)rtf.Param / 1440.0F) * document.Dpi; + if (rtf_style.rtf_par_next_tab_stop != null) { + rtf_style.rtf_par_next_tab_stop.Position = tabPos; + rtf_style.rtf_par_tab_stops.Add (rtf_style.rtf_par_next_tab_stop); + rtf_style.rtf_par_next_tab_stop = null; + } else { + rtf_style.rtf_par_tab_stops.Add (new LeftTabStop (tabPos)); + } break; case RTF.Minor.LeftIndent: - using (Graphics g = CreateGraphics ()) - rtf_style.rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * g.DpiX + 0.5F); + rtf_style.rtf_par_line_left_indent = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.FirstIndent: + rtf_style.rtf_par_first_line_indent = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.RightIndent: + rtf_style.rtf_par_line_right_indent = ((float) rtf.Param / 1440.0F) * document.Dpi; break; case RTF.Minor.QuadCenter: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Center; + rtf_style.rtf_par_align = HorizontalAlignment.Center; break; case RTF.Minor.QuadJust: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Center; + rtf_style.rtf_par_align = HorizontalAlignment.Left; break; case RTF.Minor.QuadLeft: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_par_align = HorizontalAlignment.Left; break; case RTF.Minor.QuadRight: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Right; + rtf_style.rtf_par_align = HorizontalAlignment.Right; + break; + + case RTF.Minor.SpaceAfter: + rtf_style.rtf_par_spacing_after = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.SpaceBefore: + rtf_style.rtf_par_spacing_before = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.SpaceBetween: + rtf_style.rtf_par_line_spacing = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.SpaceMultiply: + rtf_style.rtf_par_line_spacing_multiple = (rtf.Param == 1); break; } break; @@ -1543,7 +1959,8 @@ namespace System.Windows.Forms { case RTF.Minor.Row: case RTF.Minor.Line: case RTF.Minor.Par: { - FlushText(rtf, true); + if (Multiline) + FlushText (rtf, true); break; } @@ -1575,8 +1992,8 @@ namespace System.Windows.Forms { break; } - case RTF.Minor.WidowCtrl: - break; + case RTF.Minor.WidowCtrl: + break; case RTF.Minor.EmDash: { rtf_line.Append ("\u2014"); @@ -1587,7 +2004,7 @@ namespace System.Windows.Forms { rtf_line.Append ("\u2013"); break; } -/* + case RTF.Minor.LQuote: { Console.Write("\u2018"); break; @@ -1607,7 +2024,7 @@ namespace System.Windows.Forms { Console.Write("\u201D"); break; } -*/ + default: { // Console.WriteLine ("skipped special char: {0}", rtf.Minor); // rtf.SkipGroup(); @@ -1640,16 +2057,21 @@ namespace System.Windows.Forms { } */ - if (rtf_style.rtf_visible) - rtf_line.Append (str); + rtf_line.Append (str); } private void FlushText(RTF.RTF rtf, bool newline) { + FlushText (rtf, newline, false); + } + + private void FlushText(RTF.RTF rtf, bool newline, bool force) { int length; + float hanging_indent; + float left_indent; Font font; length = rtf_line.Length; - if (!newline && (length == 0)) { + if (!newline && (length == 0) && !force) { return; } @@ -1659,7 +2081,12 @@ namespace System.Windows.Forms { } font = new Font (rtf_style.rtf_rtffont.Name, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle); + if (font.Name != rtf_style.rtf_rtffont.Name && !string.IsNullOrEmpty (rtf_style.rtf_rtffont.AltName)) + font = new Font (rtf_style.rtf_rtffont.AltName, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle); + hanging_indent = -rtf_style.rtf_par_first_line_indent; + left_indent = rtf_style.rtf_par_line_left_indent - hanging_indent; + if (rtf_style.rtf_color == Color.Empty) { System.Windows.Forms.RTF.Color color; @@ -1682,30 +2109,40 @@ namespace System.Windows.Forms { if (newline && rtf_line.ToString ().EndsWith (Environment.NewLine) == false) rtf_line.Append (Environment.NewLine); - document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_rtfalign, font, rtf_style.rtf_color, - newline ? LineEnding.Rich : LineEnding.Wrap); - if (rtf_style.rtf_par_line_left_indent != 0) { - Line line = document.GetLine (rtf_cursor_y); - line.indent = rtf_style.rtf_par_line_left_indent; - } + document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_par_align, font, rtf_style.rtf_color, + rtf_style.rtf_back_color, rtf_style.rtf_text_position, rtf_style.rtf_char_offset, left_indent, hanging_indent, + rtf_style.rtf_par_line_right_indent, rtf_style.rtf_par_spacing_before, rtf_style.rtf_par_spacing_after, + rtf_style.rtf_par_line_spacing, rtf_style.rtf_par_line_spacing_multiple, + rtf_style.rtf_par_tab_stops.Clone() , rtf_style.rtf_visible, + newline ? LineEnding.Rich : LineEnding.None); } else { - Line line; + Line line = document.GetLine (rtf_cursor_y); + + if (newline) { + if (rtf_cursor_x < line.text.Length) + document.Split(line, rtf_cursor_x); + line.ending = LineEnding.Rich; + } + + line.indent = left_indent; + line.HangingIndent = hanging_indent; + line.right_indent = rtf_style.rtf_par_line_right_indent; + line.spacing_after = rtf_style.rtf_par_spacing_after; + line.spacing_before = rtf_style.rtf_par_spacing_before; + line.line_spacing = rtf_style.rtf_par_line_spacing; + line.line_spacing_multiple = rtf_style.rtf_par_line_spacing_multiple; + line.alignment = rtf_style.rtf_par_align; - line = document.GetLine (rtf_cursor_y); - line.indent = rtf_style.rtf_par_line_left_indent; if (rtf_line.Length > 0) { document.InsertString (line, rtf_cursor_x, rtf_line.ToString ()); document.FormatText (line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, - font, rtf_style.rtf_color, Color.Empty, - FormatSpecified.Font | FormatSpecified.Color); + font, rtf_style.rtf_color, rtf_style.rtf_back_color, rtf_style.rtf_text_position, rtf_style.rtf_char_offset, + rtf_style.rtf_visible, FormatSpecified.Font | FormatSpecified.Color | FormatSpecified.BackColor | + FormatSpecified.TextPosition | FormatSpecified.CharOffset | FormatSpecified.Visibility); } - if (newline) { - line = document.GetLine (rtf_cursor_y); - line.ending = LineEnding.Rich; - if (line.Text.EndsWith (Environment.NewLine) == false) - line.Text += Environment.NewLine; - } + if (newline && line.Text.EndsWith (Environment.NewLine) == false) + line.Text += Environment.NewLine; reuse_line = false; // sanity assignment - in this case we have already re-used one line. } @@ -1740,9 +2177,20 @@ namespace System.Windows.Forms { rtf_skip_count = 0; rtf_line = new StringBuilder(); rtf_style.rtf_color = Color.Empty; + rtf_style.rtf_back_color = Color.Empty; rtf_style.rtf_rtffont_size = (int)this.Font.Size; - rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_par_align = HorizontalAlignment.Left; rtf_style.rtf_rtfstyle = FontStyle.Regular; + rtf_style.rtf_text_position = TextPositioning.Normal; + rtf_style.rtf_par_spacing_after = 0; + rtf_style.rtf_par_spacing_before = 0; + rtf_style.rtf_par_line_spacing = 0; + rtf_style.rtf_par_line_spacing_multiple = false; + rtf_style.rtf_par_line_left_indent = 0; + rtf_style.rtf_par_first_line_indent = 0; + rtf_style.rtf_par_line_right_indent = 0; + rtf_style.rtf_par_tab_stops.Clear (); + rtf_style.rtf_char_offset = 0; rtf_style.rtf_rtffont = null; rtf_style.rtf_visible = true; rtf_style.rtf_skip_width = 1; @@ -1751,15 +2199,18 @@ namespace System.Windows.Forms { rtf_chars = 0; rtf.DefaultFont(this.Font.Name); - rtf_text_map = new RTF.TextMap(); - RTF.TextMap.SetupStandardTable(rtf_text_map.Table); - document.SuspendRecalc (); try { rtf.Read(); // That's it FlushText(rtf, false); + if (document.Lines > 1) { + Line last_line = document.GetLine (document.Lines); + if (last_line.text.Length == 0) { + document.Delete (last_line); + } + } } @@ -1780,10 +2231,11 @@ namespace System.Windows.Forms { rtf_section_stack.Clear(); if (IsHandleCreated) { + CalculateScrollBars (); using (var graphics = CreateGraphics()) document.RecalculateDocument(graphics, cursor_y, document.Lines, false); document.ResumeRecalc (true); - document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1); + document.InvalidateLinesAfter(document.GetLine(cursor_y)); } else { document.ResumeRecalc (false); } @@ -1822,7 +2274,7 @@ namespace System.Windows.Forms { rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry } - if ((prev_font == null) || (prev_font.Size != font.Size)) { + if ((prev_font == null) || (Math.Abs (prev_font.Size - font.Size) > 0.01)) { rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size } @@ -1873,19 +2325,20 @@ namespace System.Windows.Forms { int start = rtf.Length; int count = text.Length; - // First emit simple unicode chars as escaped - EmitEscapedUnicode (rtf, text); - // This method emits user text *only*, so it's safe to escape any reserved rtf chars // Escape '\' first, since it is used later to escape the other chars if (text.IndexOfAny (ReservedRTFChars) > -1) { - rtf.Replace ("\\", "\\\\", start, count); - rtf.Replace ("{", "\\{", start, count); - rtf.Replace ("}", "\\}", start, count); + StringBuilder sb = new StringBuilder(text); // Would it be better to just use text = text.Replace for this? + sb.Replace ("\\", "\\\\"); + sb.Replace ("{", "\\{"); + sb.Replace ("}", "\\}"); + text = sb.ToString (); } + + // Then actually emit the text, and also escape any Unicode + EmitEscapedUnicode (rtf, text); } - // The chars to be escaped use "\'" + its hexadecimal value. private void EmitEscapedUnicode (StringBuilder sb, string text) { int pos; @@ -1894,9 +2347,10 @@ namespace System.Windows.Forms { while ((pos = IndexOfNonAscii (text, start)) > -1) { sb.Append (text, start, pos - start); - int n = (int)text [pos]; - sb.Append ("\\'"); - sb.Append (n.ToString ("X")); + short n = (short)text [pos]; + sb.Append ("\\u"); + sb.Append (n.ToString ()); + sb.Append ("?"); start = pos + 1; } @@ -1918,24 +2372,182 @@ namespace System.Windows.Forms { return -1; } + static char[] GetHexChars (byte[] bytes, int length) + { + if (length > bytes.Length) + throw new ArgumentOutOfRangeException ("length"); + + var chars = new char [length * 2]; + int n; + for (int i = 0; i < length; i++) { + n = bytes [i] >> 4; + chars [i * 2] = (char)('A' - 10 + n + (((n - 10) >> 31) & ('0' - 55))); + n = bytes [i] & 0x0F; + chars [i * 2 + 1] = (char)('A' - 10 + n + (((n - 10) >> 31) & ('0' - 55))); + } + return chars; + } + + void EmitRtfPicture (PictureTag picture, StringBuilder sb) + { + if (!picture.picture.IsValid ()) { + return; + } + + int width = (int)((float)picture.picture.Width / document.Dpi * 1440f); + int height = (int)((float)picture.picture.Height / document.Dpi * 1440f); + string type = ""; + switch (picture.picture.ImageType) { + case RTF.Minor.WinMetafile: + type = "wmetafile1"; // The number should actually vary, but I don't see how it is used here at all. + break; + case RTF.Minor.EnhancedMetafile: + type = "emfblip"; + break; + case RTF.Minor.PngBlip: + type = "pngblip"; + break; + case RTF.Minor.JpegBlip: + type = "jpegblip"; + break; + } + sb.AppendFormat ("{{\\pict\\{0}\\picwgoal{1}\\pichgoal{2} ", type, width, height); + + var data = picture.picture.Data; + data.Position = 0; + if (sb.Capacity - sb.Length < data.Length) { + sb.Capacity += (int)data.Length * 2; + } + var buffer = new byte [39]; + int length; + while ((length = data.Read (buffer, 0, buffer.Length)) > 0) { + sb.AppendLine ().Append (GetHexChars (buffer, length)); + } + sb.Append ("}"); + } + + void EmitTabStops (StringBuilder sb, TabStopCollection tabs) + { + foreach (var tab in tabs) { + if (tab is DecimalTabStop) { + sb.Append ("\\tqdec"); + } else if (tab is CentredTabStop) { + sb.Append ("\\tqc"); + } else if (tab is RightTabStop) { + sb.Append ("\\tqr"); + } + sb.Append ("\\tx"); + sb.Append (Int (tab.Position / document.Dpi * 1440f)); + } + } + + void EmitPard (StringBuilder sb, ArrayList fonts, Line line, LineTag tag, TabStopCollection tabs, float ppt) + { + var first_line_indent = -line.HangingIndent; + var left_indent = line.Indent - first_line_indent; + var right_indent = line.RightIndent; + + sb.Append ("\\pard"); + // Reset to default paragraph properties + switch (line.alignment) { + case HorizontalAlignment.Left: + sb.Append ("\\ql"); + break; + case HorizontalAlignment.Center: + sb.Append ("\\qc"); + break; + case HorizontalAlignment.Right: + sb.Append ("\\qr"); + break; + } + if (Math.Abs (line.spacing_after) > ppt) { + sb.Append ("\\sa"); + sb.Append (Int (line.spacing_after / ppt)); + } + if (Math.Abs (line.spacing_before) > ppt) { + sb.Append ("\\sb"); + sb.Append (Int (line.spacing_before / ppt)); + } + if (Math.Abs (line.line_spacing) > ppt) { + sb.Append ("\\sl"); + sb.Append (Int (line.line_spacing / ppt)); + sb.Append ("\\slmult"); + sb.Append (line.line_spacing_multiple ? "1" : "0"); + } + if (Math.Abs (left_indent) > ppt) { + sb.Append ("\\li"); + sb.Append (Int (left_indent / ppt)); + } + if (Math.Abs (first_line_indent) > ppt) { + sb.Append ("\\fi"); + sb.Append (Int (first_line_indent / ppt)); + } + if (Math.Abs (right_indent) > ppt) { + sb.Append ("\\ri"); + sb.Append (Int (right_indent / ppt)); + } + if (tabs.Count > 0) { + EmitTabStops (sb, tabs); + } + } + + static void LoadParaSettings (Line line, out HorizontalAlignment line_alignment, out float spacing_after, out float spacing_before, out float line_spacing, + out bool line_spacing_multiple, out float left_indent, out float prev_left_indent, out float first_line_indent, + out float prev_first_line_indent, out float right_indent, out TabStopCollection tabs) + { + spacing_after = line.spacing_after; + spacing_before = line.spacing_before; + line_spacing = line.line_spacing; + line_spacing_multiple = line.line_spacing_multiple; + line_alignment = line.alignment; + first_line_indent = -line.HangingIndent; + left_indent = line.Indent - first_line_indent; + prev_first_line_indent = first_line_indent; + prev_left_indent = left_indent; + right_indent = line.RightIndent; + tabs = line.TabStops; + } + // start_pos and end_pos are 0-based private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) { StringBuilder sb; ArrayList fonts; ArrayList colors; Color color; + Color back_color; Font font; Line line; LineTag tag; + TextPositioning text_position; + HorizontalAlignment line_alignment; + float spacing_after; + float spacing_before; + float line_spacing; + bool line_spacing_multiple; + float left_indent; + float prev_left_indent; + float first_line_indent; + float prev_first_line_indent; + float right_indent; + TabStopCollection tabs; + TabStopCollection tabDiff; + bool emit_defaults; + float char_offset; + bool visible; int pos; int line_no; int line_len; - int i; + int i, j; int length; + float ppt; // pixels per twip + + ppt = document.Dpi / 1440f; // 1 twip = 1/20 point, 1 point = 1/72 inch, thus 1440 twips = 1 inch. + emit_defaults = false; sb = new StringBuilder(); fonts = new ArrayList(10); colors = new ArrayList(10); + tabDiff = new TabStopCollection (); // Two runs, first we parse to determine tables; // and unlike most of our processing here we work on tags @@ -1949,6 +2561,7 @@ namespace System.Windows.Forms { tag = LineTag.FindTag(start_line, pos); font = tag.Font; color = tag.Color; + back_color = Color.Empty; fonts.Add(font.Name); colors.Add(color); @@ -1972,11 +2585,18 @@ namespace System.Windows.Forms { if (tag.Color != color) { color = tag.Color; - if (!colors.Contains(color)) { + if (color != Color.Empty && !colors.Contains (color)) { colors.Add(color); } } + if (tag.BackColor != back_color) { + back_color = tag.BackColor; + if (back_color != Color.Empty && !colors.Contains (back_color)) { + colors.Add (back_color); + } + } + pos = tag.Start + tag.Length - 1; tag = tag.Next; } @@ -2008,7 +2628,7 @@ namespace System.Windows.Forms { // Emit the color table (if needed) if ((colors.Count > 1) || ((((Color)colors[0]).R != this.ForeColor.R) || (((Color)colors[0]).G != this.ForeColor.G) || (((Color)colors[0]).B != this.ForeColor.B))) { - sb.Append("{\\colortbl "); // Header and NO! default color + sb.Append("{\\colortbl;"); // Header and default color (default is needed) for (i = 0; i < colors.Count; i++) { sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R)); sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G)); @@ -2020,17 +2640,24 @@ namespace System.Windows.Forms { } sb.Append("{\\*\\generator Mono RichTextBox;}"); - // Emit initial paragraph settings - tag = LineTag.FindTag(start_line, start_pos); - sb.Append("\\pard"); // Reset to default paragraph properties - EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.Font.Name), null, tag.Font); // Font properties - sb.Append(" "); // Space separator + tag = LineTag.FindTag (start_line, start_pos); font = tag.Font; - color = (Color)colors[0]; + color = Color.Empty; + back_color = Color.Empty; + text_position = TextPositioning.Normal; + char_offset = 0; + visible = true; line = start_line; line_no = start_line.line_no; pos = start_pos; + LoadParaSettings (line, out line_alignment, out spacing_after, out spacing_before, out line_spacing, + out line_spacing_multiple, out left_indent, out prev_left_indent, out first_line_indent, + out prev_first_line_indent, out right_indent, out tabs); + + EmitPard (sb, fonts, line, tag, tabs, ppt); + EmitRTFFontProperties (sb, -1, fonts.IndexOf (tag.Font.Name), null, tag.Font); // Font properties + sb.Append(" "); // Space separator while (line_no <= end_line.line_no) { line = document.GetLine(line_no); @@ -2042,7 +2669,110 @@ namespace System.Windows.Forms { line_len = end_pos; } - while (pos < line_len) { + i = 0; + j = 0; + tabDiff.Clear (); + emit_defaults = line.TabStops.Count < tabs.Count; // If there are less tabs on the new line, we've got to start over. + while (!emit_defaults && i < tabs.Count && j < line.TabStops.Count) { + if (tabs [i].Equals (line.TabStops [j])) { + i++; + j++; + } else if (tabs [i].Position - ppt > line.TabStops [j].Position) { + // The current tabstop is after the new line's one, so we need to add one in between. + tabDiff.Add (line.TabStops [j]); + j++; + } else { + // Either the tabs are at the same position and are of different types, or this line is missing at least one. + // This in turn means we must start the line with a \pard, and re-emit all other paragraph properties. + emit_defaults = true; + } + } + if (i < tabs.Count) // We didn't reach the end of the existing tabstops, so the rest have to be removed. + emit_defaults = true; + while (!emit_defaults && j < line.TabStops.Count) { // Any new ones have to be added on the end too. + tabDiff.Add (line.TabStops[j]); + j++; + } + tabs = line.TabStops; + + if (!emit_defaults) { + length = sb.Length; + if (line.Alignment != line_alignment) { + line_alignment = line.Alignment; + switch (line_alignment) { + case HorizontalAlignment.Left: + sb.Append("\\ql"); + break; + case HorizontalAlignment.Center: + sb.Append("\\qc"); + break; + case HorizontalAlignment.Right: + sb.Append("\\qr"); + break; + } + } + + if (Math.Abs(line.spacing_after - spacing_after) > ppt) { + spacing_after = line.spacing_after; + sb.Append("\\sa"); + sb.Append(Int(spacing_after / ppt)); + } + + if (Math.Abs(line.spacing_before - spacing_before) > ppt) { + spacing_before = line.spacing_before; + sb.Append("\\sb"); + sb.Append(Int(spacing_before / ppt)); + } + + if (Math.Abs(line.line_spacing - line_spacing) > ppt) { + line_spacing = line.line_spacing; + sb.Append("\\sl"); + sb.Append(Int(line.line_spacing / ppt)); + } + + if (line.line_spacing_multiple != line_spacing_multiple) { + line_spacing_multiple = line.line_spacing_multiple; + sb.Append("\\slmult"); + sb.Append(line.line_spacing_multiple ? "1" : "0"); + } + + first_line_indent = -line.HangingIndent; + left_indent = line.Indent - first_line_indent; + + if (Math.Abs(prev_left_indent - left_indent) > ppt) { + prev_left_indent = left_indent; + sb.Append("\\li"); + sb.Append(Int(left_indent / ppt)); + } + + if (Math.Abs(prev_first_line_indent - first_line_indent) > ppt) { + prev_first_line_indent = first_line_indent; + sb.Append("\\fi"); + sb.Append(Int(first_line_indent / ppt)); + } + + if (Math.Abs(line.right_indent - right_indent) > ppt) { + right_indent = line.right_indent; + sb.Append("\\ri"); + sb.Append(Int(right_indent / ppt)); + } + + if (tabDiff.Count > 0) { + EmitTabStops(sb, tabDiff); + } + + if (length != sb.Length) { + sb.Append(" "); + } + } else { + EmitPard (sb, fonts, line, tag, tabs, ppt); + sb.Append(" "); + LoadParaSettings (line, out line_alignment, out spacing_after, out spacing_before, out line_spacing, + out line_spacing_multiple, out left_indent, out prev_left_indent, out first_line_indent, + out prev_first_line_indent, out right_indent, out tabs); + } + + while (pos < line_len && tag != null) { length = sb.Length; if (tag.Font != font) { @@ -2052,14 +2782,65 @@ namespace System.Windows.Forms { if (tag.Color != color) { color = tag.Color; - sb.Append(String.Format("\\cf{0}", colors.IndexOf(color))); + if (color != Color.Empty) + sb.Append(String.Format("\\cf{0}", colors.IndexOf(color) + 1)); + else + sb.Append("\\cf0"); + } + + if (tag.BackColor != back_color) { + back_color = tag.BackColor; + if (back_color != Color.Empty) + sb.Append(String.Format("\\cb{0}", colors.IndexOf(back_color) + 1)); + else + sb.Append("\\cb0"); + } + + if (tag.TextPosition != text_position) { + if (text_position != TextPositioning.Normal && tag.TextPosition != TextPositioning.Normal) + sb.Append("\\nosupersub"); + // Technically it is possible to have subscripts in superscript and vise versa. But that's not what we've got. + text_position = tag.TextPosition; + switch (tag.TextPosition) { + case TextPositioning.Normal: + sb.Append("\\nosupersub"); + break; + case TextPositioning.Subscript: + sb.Append("\\sub"); + break; + case TextPositioning.Superscript: + sb.Append("\\super"); + break; + } + } + + if (tag.CharOffset != char_offset) { + char_offset = tag.CharOffset; + if (char_offset >= 0) { + sb.Append("\\up"); + sb.Append(Int((char_offset / document.Dpi) * 144)); + } else { + sb.Append("\\dn"); + sb.Append(-Int((char_offset / document.Dpi) * 144)); + } + } + + if (tag.Visible != visible) { + visible = tag.Visible; + if (visible) + sb.Append("\\v0"); + else + sb.Append("\\v"); } + if (length != sb.Length) { sb.Append(" "); // Emit space to separate keywords from text } // Emit the string itself - if (line_no != end_line.line_no) { + if (tag is PictureTag) { + EmitRtfPicture((PictureTag)tag, sb); + } else if (line_no != end_line.line_no) { EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1)); } else { if (end_pos < (tag.Start + tag.Length - 1)) { @@ -2071,11 +2852,16 @@ namespace System.Windows.Forms { } pos = tag.Start + tag.Length - 1; - tag = tag.Next; + do { + tag = tag.Next; + } while (tag != null && tag.IsTextTag && tag.Length == 0); } if (pos >= line.text.Length) { if (line.ending != LineEnding.Wrap) { - sb.Append("\\par"); + // pos is incremented by the tag length, so it can be after where we want to finish. + // If we're on the last line we don't want to output \par when we're stopping before the end of the line. + if (!(line_no == end_line.line_no && pos > end_pos)) + sb.Append("\\par"); sb.Append(Environment.NewLine); } } @@ -2088,6 +2874,11 @@ namespace System.Windows.Forms { return sb; } + + int Int (float f) + { + return (int)(f + 0.5f); + } #endregion // Private Methods } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TabStops.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TabStops.cs new file mode 100644 index 00000000000..6226024cdc1 --- /dev/null +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TabStops.cs @@ -0,0 +1,258 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2015 Karl Scowen +// +// Authors: +// Karl Scowen <contact@scowencomputers.co.nz> +// +// + +using System; +using System.Collections.Generic; + +namespace System.Windows.Forms { + abstract class TabStop : IComparable<TabStop> { + float _pos = -1; + + internal float Position { + get { + return _pos; + } + + set { + if (_pos >= 0) + throw new InvalidOperationException ("Can't change Position once it has been set!"); + + _pos = value; + } + } + + internal virtual float GetInitialWidth (Line line, int pos) + { + return 0; + } + + internal abstract float CalculateRight (Line line, int pos); + + public override bool Equals (object obj) + { + return obj.GetType () == this.GetType () && Math.Abs (((TabStop)obj).Position - Position) < 0.01; + } + + public override int GetHashCode () + { + return this.GetType ().GetHashCode () ^ Position.GetHashCode (); + } + + public override string ToString () + { + return string.Format ("[{0}: Position {1}]", this.GetType().Name, Position); + } + + #region IComparable implementation + public int CompareTo (TabStop other) + { + return Position.CompareTo (other.Position); + } + + #endregion + } + + class LeftTabStop : TabStop { + internal LeftTabStop () + { + } + internal LeftTabStop (float position) + { + Position = position; + } + + internal override float GetInitialWidth (Line line, int pos) + { + return Position - line.widths[pos]; + } + + internal override float CalculateRight (Line line, int pos) + { + return Position; + } + } + + class CentredTabStop : TabStop { + internal override float CalculateRight (Line line, int pos) + { + int endIndex = line.Text.IndexOfAny (new [] {'\t', '\n', '\r'}, pos + 1); // pos is this tab's index, so look after that. + if (endIndex < 0) + endIndex = line.text.Length; + float textWidth = line.widths [endIndex] - line.widths [pos + 1]; // We use the position after this tabstop, hence pos + 1. + return Math.Max (Position - textWidth / 2f, line.widths [pos]); // We want the width until the start of the text, which is before Position, but we can't go below zero. + } + } + + internal class RightTabStop : TabStop { + internal override float CalculateRight (Line line, int pos) + { + int endIndex = line.Text.IndexOfAny (new [] {'\t', '\n', '\r'}, pos + 1); // pos is this tab's index, so look after that. + return calcWidth (line, pos, endIndex); + } + + protected float calcWidth (Line line, int pos, int endIndex) + { + if (endIndex < 0) + endIndex = line.text.Length; + float textWidth = line.widths [endIndex] - line.widths [pos + 1]; // We use the position after this tabstop, hence pos + 1. + return Math.Max (Position - textWidth, line.widths [pos]); + } + } + + internal class DecimalTabStop : RightTabStop { + internal override float CalculateRight (Line line, int pos) + { + // This is simply a right-align tabstop that regards the decimal as the end. + int endIndex = line.Text.IndexOfAny (new [] {'\t', '\n', '\r', '.'}, pos + 1); // pos is this tab's index, so look after that. + return calcWidth (line, pos, endIndex); + } + } + + internal class TabStopCollection : IList<TabStop> { + SortedList<TabStop, TabStop> tabs = new SortedList<TabStop, TabStop> (); + + public TabStopCollection Clone () + { + var n = new TabStopCollection (); + foreach (var tab in tabs.Keys) { + n.tabs.Add (tab, null); + } + return n; + } + + public int IndexOf (TabStop tab) + { + return tabs.IndexOfKey (tab); + } + + public void Insert (int index, TabStop item) + { + throw new NotSupportedException ("Not relevant to sorted data!"); + } + + public void RemoveAt (int index) + { + tabs.RemoveAt (index); + } + + public TabStop this [int index] { + get { + return tabs.Keys [index]; + } + set { + throw new NotSupportedException ("Not relevant to sorted data!"); + } + } + + #region ICollection implementation + public void Add (TabStop tab) + { + tabs.Add (tab, null); + } + + public void Clear () + { + tabs.Clear (); + } + + public bool Contains (TabStop tab) + { + return tabs.ContainsKey (tab); + } + + public void CopyTo (TabStop[] array, int arrayIndex) + { + tabs.Keys.CopyTo (array, arrayIndex); + } + + public TabStop[] ToArray () + { + var arr = new TabStop [Count]; + CopyTo (arr, 0); + return arr; + } + + public int[] ToPosArray () + { + var arr = new int [Count]; + for (int i = 0; i < Count; i++) { + arr [i] = (int)this [i].Position; + } + return arr; + } + + public bool Remove (TabStop tab) + { + return tabs.Remove (tab); + } + + public int Count { + get { + return tabs.Count; + } + } + + bool ICollection<TabStop>.IsReadOnly { + get { + return false; + } + } + #endregion + + #region IEnumerable implementation + public IEnumerator<TabStop> GetEnumerator () + { + return tabs.Keys.GetEnumerator (); + } + #endregion + + #region IEnumerable implementation + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + #endregion + + public override bool Equals (object obj) + { + var other = obj as TabStopCollection; + if (other == null || other.Count != this.Count) + return false; + + for (int i = 0; i < Count; i++) { + if (!tabs.Keys [i].Equals (other.tabs.Keys [i])) + return false; + } + return true; + } + + public override int GetHashCode () + { + // I don't like warnings, but I honestly don't care about the hash code. + return base.GetHashCode (); + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs index a2cc8560ffd..b4440143b76 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok pbartok@novell.com +// Karl Scowen <contact@scowencomputers.co.nz> // // @@ -116,8 +117,7 @@ namespace System.Windows.Forms current_link = null; show_caret_w_selection = (this is TextBox); document = new Document(this); - document.WidthChanged += new EventHandler(document_WidthChanged); - document.HeightChanged += new EventHandler(document_HeightChanged); + document.SizeChanged += new EventHandler<Document.SizeChangedEventArgs> (document_SizeChanged); //document.CaretMoved += new EventHandler(CaretMoved); document.Wrap = false; click_last = DateTime.Now; @@ -296,8 +296,7 @@ namespace System.Windows.Forms if (value == actual_border_style) return; - if (actual_border_style != BorderStyle.Fixed3D || value != BorderStyle.Fixed3D) - Invalidate (); + Invalidate (); actual_border_style = value; document.UpdateMargins (); @@ -617,7 +616,10 @@ namespace System.Windows.Forms Line line = null; for (int i = 1; i <= document.Lines; i++) { line = document.GetLine (i); - sb.Append(line.text.ToString ()); + if (i == document.Lines) + sb.Append(line.TextWithoutEnding ()); + else + sb.Append(line.text.ToString ()); } return sb.ToString(); @@ -2043,22 +2045,24 @@ namespace System.Windows.Forms Invalidate(); } - internal void CalculateScrollBars () + internal bool CalculateScrollBars () { - // FIXME - need separate calculations for center and right alignment + var old_canvas_width = canvas_width; + SizeControls (); - if (document.Width >= document.ViewPortWidth) { + if (document.Width > document.ViewPortWidth) { hscroll.SetValues (0, Math.Max (1, document.Width), -1, document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth); if (document.multiline) hscroll.Enabled = true; } else { hscroll.Enabled = false; + hscroll.Value = hscroll.Minimum; hscroll.Maximum = document.ViewPortWidth; } - if (document.Height >= document.ViewPortHeight) { + if (document.Height > document.ViewPortHeight) { vscroll.SetValues (0, Math.Max (1, document.Height), -1, document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight); if (document.multiline) @@ -2109,16 +2113,16 @@ namespace System.Windows.Forms PositionControls (); SizeControls (); //Update sizings now we've decided whats visible - } - private void document_WidthChanged (object sender, EventArgs e) - { - CalculateScrollBars(); + return (canvas_width != old_canvas_width); } - private void document_HeightChanged (object sender, EventArgs e) + private void document_SizeChanged (object sender, Document.SizeChangedEventArgs e) { - CalculateScrollBars(); + var canvas_width_changed = CalculateScrollBars (); + if (e.HeightChanged && canvas_width_changed) + CalculateDocument (); // Viewport has changed due to the document change, update the document. + // TODO: technically the opposite situation could happen too, where a document width change causes a change in canvas height. } private void ScrollLinks (int xChange, int yChange) @@ -2311,40 +2315,41 @@ namespace System.Windows.Forms // If the caret moves to the left outside the visible area, we jump the document into view, not just one // character, but 1/3 of the width of the document // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible + // For comparison, in Windows 8.1 / .Net 4: + // Multiline: as above, but 1/4 + // Single line: either direction with the cursors jumps 1/4 + // Both are irrespective of alignment. // Handle horizontal scrolling - if (document.CaretLine.alignment == HorizontalAlignment.Left) { - // Check if we moved out of view to the left - if (pos.X < (document.ViewPortX)) { - do { - if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) { - hscroll.SafeValueSet (hscroll.Value - document.ViewPortWidth / 3); - } else { - hscroll.Value = hscroll.Minimum; - } - } while (hscroll.Value > pos.X); - } + // Check if we moved out of view to the left + if (pos.X < (document.ViewPortX)) { + do { + var newVal = hscroll.Value - document.ViewPortWidth / 3 - 1; // - 1 so that we're guaranteed to move, even if document.ViewPortWidth is < 3. + if (newVal >= hscroll.Minimum) { + hscroll.SafeValueSet (newVal); + } else { + hscroll.Value = hscroll.Minimum; + } + } while (hscroll.Value > pos.X); + } - // Check if we moved out of view to the right - if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) { - if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) { - if (pos.X - document.ViewPortWidth >= 0) { - hscroll.SafeValueSet (pos.X - document.ViewPortWidth + 1); - } else { - hscroll.Value = 0; - } + // Check if we moved out of view to the right + if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) { + int newVal; + if (Multiline) { + newVal = pos.X - document.ViewPortWidth + 1; + } else { + newVal = pos.X - document.ViewPortWidth * 2 / 3 + 1; + } + if (newVal <= hscroll.Maximum - document.ViewPortWidth + 1) { + if (newVal >= 0) { + hscroll.SafeValueSet (newVal); } else { - hscroll.Value = hscroll.Maximum; + hscroll.Value = 0; } + } else { + hscroll.Value = hscroll.Maximum - document.ViewPortWidth + 1; } - } else if (document.CaretLine.alignment == HorizontalAlignment.Right) { -// hscroll.Value = pos.X; - -// if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) { -// hscroll.Value = hscroll.Maximum; -// } - } else { - // FIXME - implement center cursor alignment } if (Text.Length > 0) @@ -2354,7 +2359,10 @@ namespace System.Windows.Forms return; // Handle vertical scrolling - height = document.CaretLine.Height + 1; + height = document.CaretLine.Height; + + if (document.CaretLine.line_no < document.Lines) + height += 1; // Add a bit of room on the bottom if there are more lines - but don't scroll past the bottom when ther aren't. if (pos.Y < document.ViewPortY) vscroll.SafeValueSet (pos.Y); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs index 24859dbf3fb..cf65c990cbf 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok pbartok@novell.com +// Karl Scowen <contact@scowencomputers.co.nz> // // @@ -47,6 +48,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Text; using System.Text; @@ -71,6 +73,17 @@ namespace System.Windows.Forms { BackColor = 2, Font = 4, Color = 8, + TextPosition = 16, + CharOffset = 32, + Visibility = 64, + + All = 126 + } + + internal enum TextPositioning { + Normal, + Superscript, + Subscript } internal enum CaretDirection { @@ -103,7 +116,7 @@ namespace System.Windows.Forms { None = 0 } - + internal class Document : ICloneable, IEnumerable { #region Structures // FIXME - go through code and check for places where @@ -224,7 +237,7 @@ namespace System.Windows.Forms { internal int viewport_x; internal int viewport_y; // The visible area of the document internal int offset_x; - internal int offset_y; + internal int offset_y; // Never assigned to except in constructor, and a property that is also never assigned to? internal int viewport_width; internal int viewport_height; @@ -240,6 +253,8 @@ namespace System.Windows.Forms { internal int left_margin = 2; // A left margin for all lines internal int top_margin = 2; internal int right_margin = 2; + + internal float dpi; #endregion // Local Variables #region Constructors @@ -301,6 +316,15 @@ namespace System.Windows.Forms { #endregion #region Internal Properties + + internal float Dpi { + get { + if (dpi > 0) + return dpi; + return TextRenderer.GetDpi ().Height; + } + } + internal Line Root { get { return document; @@ -400,7 +424,8 @@ namespace System.Windows.Forms { internal int Length { get { - return char_count + lines - 1; // Add \n for each line but the last + var lastLine = GetLine (lines); + return char_count - LineEndingLength (lastLine.ending); } } @@ -683,12 +708,8 @@ namespace System.Windows.Forms { } private void IncrementLines(int line_no) { - int current; - - current = this.lines; - while (current >= line_no) { - GetLine(current).line_no++; - current--; + foreach (var line in TransverseLines(this.lines, line_no)) { + line.line_no++; } return; } @@ -868,19 +889,27 @@ namespace System.Windows.Forms { return; } + var prev_line_pos = new Point(line.X, line.Y); + var prev_line_bottom = line.Y + line.Height; + var prev_pos_width = line.widths[pos]; + float prev_pos1_width = (line.widths.Length > pos + 1) ? line.widths[pos + 1] : prev_pos_width; + // Optimize invalidation based on Line alignment bool height_changed; using (var graphics = owner.CreateGraphics()) height_changed = RecalculateDocument(graphics, line.line_no, line.line_no, true); + var x = Math.Min(prev_line_pos.X, line.X); + var y = Math.Min(prev_line_pos.Y, line.Y); + var h = Math.Max(prev_line_bottom, line.Y + line.Height) - y; if (height_changed) { // Lineheight changed, invalidate the rest of the document - if ((line.Y - viewport_y) >=0 ) { + if ((y - viewport_y) >=0 ) { // We formatted something that's in view, only draw parts of the screen owner.Invalidate(new Rectangle( offset_x, - line.Y - viewport_y + offset_y, + y - viewport_y + offset_y, viewport_width, - owner.Height - (line.Y - viewport_y))); + owner.Height - (y - viewport_y))); } else { // The tag was above the visible area, draw everything owner.Invalidate(); @@ -889,28 +918,28 @@ namespace System.Windows.Forms { switch(line.alignment) { case HorizontalAlignment.Left: { owner.Invalidate(new Rectangle( - line.X + ((int)line.widths[pos] - viewport_x - 1) + offset_x, - line.Y - viewport_y + offset_y, + x + ((int)Math.Max(line.widths[pos], prev_pos_width) - viewport_x - 1) + offset_x, + y - viewport_y + offset_y, viewport_width, - line.height + 1)); + h + 1)); break; } case HorizontalAlignment.Center: { owner.Invalidate(new Rectangle( - line.X + offset_x, - line.Y - viewport_y + offset_y, + x + offset_x, + y - viewport_y + offset_y, viewport_width, - line.height + 1)); + h + 1)); break; } case HorizontalAlignment.Right: { owner.Invalidate(new Rectangle( - line.X + offset_x, - line.Y - viewport_y + offset_y, - (int)line.widths[pos + 1] - viewport_x + line.X, - line.height + 1)); + x + offset_x, + y - viewport_y + offset_y, + (int)Math.Max(line.widths[pos + ((line.widths.Length > pos + 1) ? 1 : 0)], prev_pos1_width) - viewport_x + line.X, + h + 1)); break; } } @@ -1248,6 +1277,14 @@ namespace System.Windows.Forms { internal void PositionCaret(Line line, int pos) { caret.tag = line.FindTag (pos); + if (pos == caret.tag.Start - 1 && caret.tag.Length != 0 && caret.tag.Previous != null) + caret.tag = caret.tag.Previous; + // When we're at a tag boundary we want the cursor in the previous (left) tag + // whereas FindTag(pos) gets the next (right) tag. LineTag.Start is 1-based. + + if (pos > line.TextLengthWithoutEnding()) + pos = line.TextLengthWithoutEnding(); + // We don't want the caret after the line ending. MoveCaretToTextTag (); @@ -1256,20 +1293,15 @@ namespace System.Windows.Forms { if (owner.IsHandleCreated) { if (owner.Focused) { - if (caret.height != caret.tag.Height) + if (caret.height != caret.tag.DrawnHeight) { + caret.height = caret.tag.DrawnHeight; XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, - offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + } + SetCaretPos(); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); } - - // We set this at the end because we use the heights to determine whether or - // not we need to recreate the caret - caret.height = caret.tag.Height; - } internal void PositionCaret(int x, int y) { @@ -1278,17 +1310,20 @@ namespace System.Windows.Forms { } caret.tag = FindCursor(x, y, out caret.pos); + + if (caret.pos > caret.tag.Line.TextLengthWithoutEnding()) + caret.pos = caret.tag.Line.TextLengthWithoutEnding(); + // Don't allow the caret to be positioned after the line ending. + // This was happening with the up and down arrows due to how FindCursor works. MoveCaretToTextTag (); caret.line = caret.tag.Line; - caret.height = caret.tag.Height; + caret.height = caret.tag.DrawnHeight; if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) { XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, - (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x + offset_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + SetCaretPos(); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); @@ -1297,9 +1332,7 @@ namespace System.Windows.Forms { internal void CaretHasFocus() { if ((caret.tag != null) && owner.IsHandleCreated) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, - offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + SetCaretPos(); DisplayCaret (); } @@ -1337,17 +1370,15 @@ namespace System.Windows.Forms { // font is larger than the line (line recalculations // ignore empty tags) in which case we make it equal // the line height and then when text is entered - if (caret.tag.Height > caret.tag.Line.Height) { - caret.height = caret.line.height; + if (caret.tag.DrawnHeight > caret.tag.Line.TextHeight) { + caret.height = caret.line.TextHeight; } else { - caret.height = caret.tag.Height; + caret.height = caret.tag.DrawnHeight; } if (owner.Focused) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos (owner.Handle, - offset_x + (int) caret.tag.Line.widths [caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + viewport_y + caret_shift); + SetCaretPos(); DisplayCaret (); } @@ -1361,23 +1392,30 @@ namespace System.Windows.Forms { MoveCaretToTextTag (); - if (caret.tag.Height != caret.height) { - caret.height = caret.tag.Height; + if (caret.tag.DrawnHeight != caret.height) { + caret.height = caret.tag.DrawnHeight; if (owner.Focused) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); } } if (owner.Focused) { - XplatUI.SetCaretPos(owner.Handle, - offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + SetCaretPos(); DisplayCaret (); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); } + void SetCaretPos () + { + XplatUI.SetCaretPos (owner.Handle, + (int)Math.Min(offset_x + caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + viewport_width - caret.tag.Line.right_indent - caret_width), // Limit X, because whitespace can be outside this. + (int)(offset_y + caret.line.Y + caret.line.SpacingBefore + caret.tag.OffsetY - + caret.tag.CharOffset + caret.tag.Shift - viewport_y + caret_shift)); + } + internal void DisplayCaret() { if (!owner.IsHandleCreated) { return; @@ -1417,6 +1455,10 @@ namespace System.Windows.Forms { // FIXME should we use IsWordSeparator to detect whitespace, instead // of looking for actual spaces in the Word move cases? + Line currentLine = caret.line; + int currentPos = caret.pos; + LineTag currentTag = caret.tag; + bool nowrap = false; switch(direction) { case CaretDirection.CharForwardNoWrap: @@ -1444,7 +1486,7 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.CharBackNoWrap: @@ -1452,12 +1494,10 @@ namespace System.Windows.Forms { goto case CaretDirection.CharBack; case CaretDirection.CharBack: { if (caret.pos > 0) { - // caret.pos--; // folded into the if below + caret.pos--; - if (--caret.pos > 0) { - if (caret.tag.Start > caret.pos) { - caret.tag = caret.tag.Previous; - } + if (caret.tag.Start > caret.pos && caret.tag.Previous != null) { + caret.tag = caret.tag.Previous; } } else { if (caret.line.line_no > 1 && !nowrap) { @@ -1467,7 +1507,7 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.WordForward: { @@ -1493,7 +1533,7 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.WordBack: { @@ -1525,31 +1565,31 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.LineUp: { if (caret.line.line_no > 1) { int pixel; - pixel = (int)caret.line.widths[caret.pos]; + pixel = (int)caret.line.widths[caret.pos] + caret.line.align_shift; PositionCaret(pixel, GetLine(caret.line.line_no - 1).Y); DisplayCaret (); } - return; + break; } case CaretDirection.LineDown: { if (caret.line.line_no < lines) { int pixel; - pixel = (int)caret.line.widths[caret.pos]; + pixel = (int)caret.line.widths[caret.pos] + caret.line.align_shift; PositionCaret(pixel, GetLine(caret.line.line_no + 1).Y); DisplayCaret (); } - return; + break; } case CaretDirection.Home: { @@ -1558,7 +1598,7 @@ namespace System.Windows.Forms { caret.tag = caret.line.tags; UpdateCaret(); } - return; + break; } case CaretDirection.End: { @@ -1567,7 +1607,7 @@ namespace System.Windows.Forms { caret.tag = LineTag.FindTag(caret.line, caret.pos); UpdateCaret(); } - return; + break; } case CaretDirection.PgUp: { @@ -1576,17 +1616,20 @@ namespace System.Windows.Forms { owner.vscroll.Value = 0; Line line = GetLine (1); PositionCaret (line, 0); + break; } int y_offset = caret.line.Y + caret.line.height - 1 - viewport_y; + int expected_y = viewport_y - viewport_height; int index; - LineTag top = FindCursor ((int) caret.line.widths [caret.pos], - viewport_y - viewport_height, out index); + LineTag top = FindCursor ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + expected_y, out index); owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height); - PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y); + PositionCaret ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + (expected_y >= 0) ? y_offset + viewport_y : 0); - return; + break; } case CaretDirection.PgDn: { @@ -1595,23 +1638,26 @@ namespace System.Windows.Forms { owner.vscroll.Value = owner.vscroll.Maximum - viewport_height + 1; Line line = GetLine (lines); PositionCaret (line, line.TextLengthWithoutEnding()); + break; } int y_offset = caret.line.Y - viewport_y; + int expected_y = viewport_y + viewport_height; int index; - LineTag top = FindCursor ((int) caret.line.widths [caret.pos], - viewport_y + viewport_height, out index); + LineTag top = FindCursor ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + expected_y, out index); owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height); - PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y); + PositionCaret ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + (expected_y <= document_y - viewport_height) ? y_offset + viewport_y : document_y); - return; + break; } case CaretDirection.CtrlPgUp: { PositionCaret(0, viewport_y); DisplayCaret (); - return; + break; } case CaretDirection.CtrlPgDn: { @@ -1627,7 +1673,7 @@ namespace System.Windows.Forms { } PositionCaret(line, line.Text.Length); DisplayCaret (); - return; + break; } case CaretDirection.CtrlHome: { @@ -1636,7 +1682,7 @@ namespace System.Windows.Forms { caret.tag = caret.line.tags; UpdateCaret(); - return; + break; } case CaretDirection.CtrlEnd: { @@ -1645,7 +1691,7 @@ namespace System.Windows.Forms { caret.tag = LineTag.FindTag(caret.line, caret.pos); UpdateCaret(); - return; + break; } case CaretDirection.SelectionStart: { @@ -1654,7 +1700,7 @@ namespace System.Windows.Forms { caret.tag = selection_start.tag; UpdateCaret(); - return; + break; } case CaretDirection.SelectionEnd: { @@ -1663,22 +1709,38 @@ namespace System.Windows.Forms { caret.tag = selection_end.tag; UpdateCaret(); - return; + break; } } + + if ((caret.pos != currentPos || caret.line != currentLine) && currentTag.Length == 0) { + // Remove the empty tag it was previously on. + if (currentTag.Previous != null) { + currentTag.Previous.Next = currentTag.Next; + } else if (currentTag.Next != null) { + // update line.tags, but don't set it to null! + currentLine.tags = currentTag.Next; + } + if (currentTag.Next != null) + currentTag.Next.Previous = currentTag.Previous; + } } internal void DumpDoc () { - Console.WriteLine ("<doc lines='{0}'>", lines); + Console.WriteLine ("<doc lines='{0}' width='{1}' height='{2}' ownerwidth='{3}' ownerheight='{4}'>", + lines, document_x, document_y, owner.Width, owner.Height); for (int i = 1; i <= lines ; i++) { Line line = GetLine (i); - Console.WriteLine ("<line no='{0}' ending='{1}'>", line.line_no, line.ending); + Console.WriteLine ("<line no='{0}' ending='{1}' x='{2}' y='{3}' width='{4}' height='{5}' indent='{6}' hanging-indent='{7}' right-indent='{8}'>", + line.line_no, line.ending, line.X, line.Y, line.Width, line.Height, line.Indent, line.HangingIndent, line.RightIndent); LineTag tag = line.tags; while (tag != null) { - Console.Write ("\t<tag type='{0}' span='{1}->{2}' font='{3}' color='{4}'>", - tag.GetType (), tag.Start, tag.Length, tag.Font, tag.Color); + Console.Write ("\t<tag type='{0}' span='{1}->{2}' font='{3}' color='{4}' position='{5}' " + + "charoffset='{6}' x='{7}' width='{8}' height='{11}' ascent='{9}' descent='{10}'>", + tag.GetType (), tag.Start, tag.Length, tag.Font, tag.Color, tag.TextPosition, + tag.CharOffset, tag.X, tag.Width, tag.Ascent, tag.Descent, tag.MaxHeight()); Console.Write (tag.Text ()); Console.WriteLine ("</tag>"); tag = tag.Next; @@ -1713,7 +1775,9 @@ namespace System.Windows.Forms { StringBuilder text; // String representing the current line int line_no; Color tag_color; + Color tag_backcolor; Color current_color; + Color current_backcolor; // First, figure out from what line to what line we need to draw GetVisibleLineIndexes (clip, out start, out end); @@ -1730,7 +1794,7 @@ namespace System.Windows.Forms { /// Make sure that we aren't drawing one more line then we need to line = GetLine (end - 1); - if (line != null && clip.Bottom == offset_y + line.Y + line.height - viewport_y) + if (line != null && clip.Bottom == offset_y + line.Y + (int)line.SpacingBefore + line.height - viewport_y) end--; line_no = start; @@ -1748,15 +1812,15 @@ namespace System.Windows.Forms { g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), offset_x + selection_start.line.widths [selection_start.pos] + selection_start.line.X - viewport_x, - offset_y + selection_start.line.Y, + offset_y + selection_start.line.Y, (selection_end.line.X + selection_end.line.widths [selection_end.pos]) - (selection_start.line.X + selection_start.line.widths [selection_start.pos]), - selection_start.line.height); + selection_start.line.height); } while (line_no <= end) { line = GetLine (line_no); - float line_y = line.Y - viewport_y + offset_y; + float line_y = line.Y - viewport_y + offset_y + line.SpacingBefore; tag = line.tags; if (!calc_pass) { @@ -1792,35 +1856,28 @@ namespace System.Windows.Forms { } else if (multiline) { // lets draw some selection baby!! (non multiline selection is drawn outside the loop) g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), - offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x, - line_y, line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1], - line.height); + offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x, line_y - line.SpacingBefore, + line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1], line.height); } } - current_color = line.tags.ColorToDisplay; while (tag != null) { // Skip empty tags - if (tag.Length == 0) { + if (tag.Length == 0 || !tag.Visible) { tag = tag.Next; continue; } - if (((tag.X + tag.Width) < (clip.Left - viewport_x - offset_x)) && - (tag.X > (clip.Right - viewport_x - offset_x))) { + if (((tag.X + tag.Width) < (clip.Left + viewport_x - offset_x)) || + (tag.X > (clip.Right + viewport_x - offset_x))) { + // Don't draw a tag that is horizontally outside the visible region. tag = tag.Next; continue; } - if (tag.BackColor != Color.Empty) { - g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (tag.BackColor), - offset_x + tag.X + line.X - viewport_x, - line_y + tag.Shift, tag.Width, line.height); - } - tag_color = tag.ColorToDisplay; - current_color = tag_color; + tag_backcolor = tag.BackColor; if (!owner.Enabled) { Color a = tag.Color; @@ -1832,26 +1889,36 @@ namespace System.Windows.Forms { } int tag_pos = tag.Start; - current_color = tag_color; while (tag_pos < tag.Start + tag.Length) { int old_tag_pos = tag_pos; if (tag_pos >= line_selection_start && tag_pos < line_selection_end) { current_color = ThemeEngine.Current.ColorHighlightText; tag_pos = Math.Min (tag.End, line_selection_end); + current_backcolor = Color.Empty; } else if (tag_pos < line_selection_start) { current_color = tag_color; tag_pos = Math.Min (tag.End, line_selection_start); + current_backcolor = tag_backcolor; } else { current_color = tag_color; tag_pos = tag.End; + current_backcolor = tag_backcolor; + } + + if (current_backcolor != Color.Empty && current_backcolor != owner.BackColor) { + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (current_backcolor), + offset_x + line.widths [old_tag_pos - 1] + line.X - viewport_x, + line_y - line.SpacingBefore, + line.widths [Math.Min (tag.Start + tag.Length, tag_pos) - 1] - line.widths [old_tag_pos - 1], + line.height); } Rectangle text_size; tag.Draw (g, current_color, offset_x + line.X - viewport_x, - line_y + tag.Shift, + line_y + tag.Shift - tag.CharOffset, old_tag_pos - 1, Math.Min (tag.Start + tag.Length, tag_pos) - 1, text.ToString (), out text_size, tag.IsLink); @@ -1975,7 +2042,21 @@ namespace System.Windows.Forms { internal void Insert (Line line, int pos, bool update_caret, string s) { - Insert (line, pos, update_caret, s, line.FindTag (pos)); + LineTag tag = line.FindTag(pos); + if (tag.Length != 0) { + if (tag.Start == pos + 1) { // pos is zero-based, tag.Start and tag.End are one-based. + // Check for empty tags before this one at the same position + var t = tag.Previous; + while (t != null && t.End == pos + 1) { + if (t.Length == 0) { + tag = t; + break; + } + t = t.Previous; + } + } // There will never be empty tags after this one, because FindTag gets the last tag at the position. + } + Insert (line, pos, update_caret, s, tag); } // Insert text at the given position; use formatting at insertion point for inserted text @@ -2004,9 +2085,11 @@ namespace System.Windows.Forms { // There are no line feeds in our text to be pasted if (break_index == s.Length) { line.InsertString (pos, s, tag); + CharCount += s.Length; } else { // Add up to the first line feed to our current position line.InsertString (pos, s.Substring (0, break_index + LineEndingLength (ending)), tag); + CharCount += break_index + LineEndingLength (ending); // Split the rest of the original line to a new line Split (line, pos + (break_index + LineEndingLength (ending))); @@ -2035,15 +2118,13 @@ namespace System.Windows.Forms { // Add the remainder of the insert text to the split // part of the original line + CharCount += s.Length - break_index; split_line.InsertString (0, s.Substring (break_index)); } // Allow the document to recalculate things ResumeRecalc (false); - // Update our character count - CharCount += s.Length; - UpdateView (line, lines - old_line_count + 1, pos); // Move the caret to the end of the inserted text if requested @@ -2191,8 +2272,15 @@ namespace System.Windows.Forms { if (!multiline) { UpdateView (line, lines, pos); owner.Invalidate (); - } else + } else { + if (line.line_no > 1) { + // If the previous line is wrapped, we update that too in case the wrap point has changed. + var l = GetLine(line.line_no - 1); + if (l != null && (l.ending == LineEnding.None || l.ending == LineEnding.Wrap)) + line = l; + } UpdateView (line, pos); + } } // Deletes a character at or after the given position (depending on forward); it will not delete past line limits @@ -2349,7 +2437,9 @@ namespace System.Windows.Forms { // cover the easy case first if (pos == line.text.Length) { - Add (line.line_no + 1, String.Empty, line.alignment, tag.Font, tag.Color, line.ending); + Add (line.line_no + 1, String.Empty, line.alignment, tag.Font, tag.Color, tag.BackColor, tag.TextPosition, + tag.CharOffset, line.Indent, line.HangingIndent, line.RightIndent, line.spacing_before, line.spacing_after, + line.line_spacing, line.line_spacing_multiple, line.tab_stops, tag.Visible, line.ending); new_line = GetLine (line.line_no + 1); @@ -2382,7 +2472,10 @@ namespace System.Windows.Forms { } // We need to move the rest of the text into the new line - Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.Font, tag.Color, line.ending); + Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.Font, tag.Color, + tag.BackColor, tag.TextPosition, tag.CharOffset, line.Indent, line.HangingIndent, line.RightIndent, + line.spacing_before, line.spacing_after, line.line_spacing, line.line_spacing_multiple, line.tab_stops, + tag.Visible, line.ending); // Now transfer our tags from this line to the next new_line = GetLine(line.line_no + 1); @@ -2515,12 +2608,19 @@ namespace System.Windows.Forms { internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, Color color, LineEnding ending) { + Add (LineNo, Text, align, font, color, Color.Empty, TextPositioning.Normal, + 0, 0, 0, 0, 0, 0, 0, false, new TabStopCollection(), true, ending); + } + + internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, Color color, Color back_color, + TextPositioning text_position, float char_offset, float left_indent, float hanging_indent, + float right_indent, float spacing_before, float spacing_after, float line_spacing, + bool line_spacing_multiple, TabStopCollection tab_stops, bool visible, LineEnding ending) + { Line add; Line line; int line_no; - CharCount += Text.Length; - if (LineNo<1 || Text == null) { if (LineNo<1) { throw new ArgumentNullException("LineNo", "Line numbers must be positive"); @@ -2529,7 +2629,10 @@ namespace System.Windows.Forms { } } - add = new Line (this, LineNo, Text, align, font, color, ending); + CharCount += Text.Length; + + add = new Line (this, LineNo, Text, align, font, color, back_color, text_position, char_offset, left_indent, + hanging_indent, right_indent, spacing_before, spacing_after, line_spacing, line_spacing_multiple, tab_stops, visible, ending); line = document; while (line != sentinel) { @@ -2598,7 +2701,7 @@ namespace System.Windows.Forms { Delete (line); } - private void Delete(Line line1) { + internal void Delete(Line line1) { Line line2;// = new Line(); Line line3; @@ -3202,7 +3305,9 @@ namespace System.Windows.Forms { int selection_start_pos = LineTagToCharIndex (selection_start.line, selection_start.pos); SuspendRecalc (); - // First, delete any selected text + var formatTag = selection_start.tag; + + // Delete any selected text if ((selection_start.pos != selection_end.pos) || (selection_start.line != selection_end.line)) { if (selection_start.line == selection_end.line) { undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); @@ -3244,9 +3349,23 @@ namespace System.Windows.Forms { } } + if (!String.IsNullOrEmpty(s)) { + int old_line_count = lines; + Insert(selection_start.line, selection_start.pos, false, s); + Line end_line; + int end_pos; + if (lines == old_line_count) { + end_line = selection_start.line; + end_pos = selection_start.pos + s.Length + 1; + } else { + end_line = GetLine(selection_start.line.line_no + lines - old_line_count); + end_pos = end_line.text.Length; + } + FormatText(selection_start.line, selection_start.pos + 1, end_line, end_pos, formatTag); // 0-base to 1-base... + undo.RecordInsertString(selection_start.line, selection_start.pos, s); + } + - Insert(selection_start.line, selection_start.pos, false, s); - undo.RecordInsertString (selection_start.line, selection_start.pos, s); Line begin_update_line = selection_start.line; int begin_update_pos = selection_start.pos; @@ -3279,6 +3398,11 @@ namespace System.Windows.Forms { ResumeRecalc (false); PositionCaret (selection_start.line, selection_start.pos); + + if (begin_update_line.line_no > selection_start.line.line_no) { + begin_update_line = selection_start.line; + begin_update_pos = selection_start.pos; + } UpdateView (begin_update_line, selection_end.line.line_no - begin_update_line.line_no, begin_update_pos); } @@ -3297,7 +3421,7 @@ namespace System.Windows.Forms { start = chars; chars += line.text.Length; - if (index <= chars) { + if (index < chars) { // we found the line tag = line.tags; @@ -3410,6 +3534,56 @@ namespace System.Windows.Forms { return null; } + internal IEnumerable<Line> TransverseLines (int start, int end) + { + Line l, c, r, prev = null; + bool r2l = start > end; + int number; + if (r2l) { + // swap start and end so that start is less than end + int s = start; + start = end; + end = s; + } + c = document; + while (c != null && c != sentinel) { + l = c.left; + r = c.right; + + if (((r2l && c.line_no < end) || (!r2l && c.line_no > start)) && (r2l ? r : l) != sentinel && (r2l ? r : l) != prev) { + // There's no point going further this way if we're just finding lines we don't want! + c = r2l ? r : l; + continue; + } + + number = c.line_no; + if (number >= start && number <= end) + yield return c; + + if ((r2l && number <= start) || (!r2l && number >= end)) + yield break; // We're done here, no need to look further. + + if ((r2l ? l : r) != sentinel) { + c = r2l ? l : r; + } else { + // If we're on the first-side node, the parent is finished with too (continues up tree), otherwise we're only done with the current node. + // We don't want to come back to first-side nodes we've already done when we do the new parent. + // The highest node we discard is going to be a first-side node, because we're discarding all second-side nodes we run into. + // The exception is when we run off the top, which is just fine too, because we're done. + // But the highest node we discard is already visited, so that is the one we're not allowed back to -- anything higher needs visiting still. + prev = c; + c = c.parent; + // The xor inverts the condition when we're going right-to-left, and therefore trims non-right (i.e. left) branches. + // With both forwards and reverse transversal, prev will be given the first-side node. + while (c != null && c.parent != null && c.right == prev ^ r2l) { + prev = c; + c = c.parent; + } + // And prev is now the previous first-side node, unless we happen to have none remaining! + } + } + } + /// <summary>Retrieve the previous tag; walks line boundaries</summary> internal LineTag PreviousTag(LineTag tag) { Line l; @@ -3539,30 +3713,45 @@ namespace System.Windows.Forms { return tag; } + public void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, LineTag copyFrom) { + FormatText(start_line, start_pos, end_line, end_pos, copyFrom.Font, copyFrom.Color, + copyFrom.BackColor, copyFrom.TextPosition, copyFrom.CharOffset, copyFrom.Visible, FormatSpecified.All); + } + + internal void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, Font font, + Color color, Color back_color, FormatSpecified specified) + { + FormatText (start_line, start_pos, end_line, end_pos, font, color, back_color, + TextPositioning.Normal, 0, true, specified); + } + /// <summary>Format area of document in specified font and color</summary> /// <param name="start_pos">1-based start position on start_line</param> /// <param name="end_pos">1-based end position on end_line </param> internal void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, Font font, - Color color, Color back_color, FormatSpecified specified) + Color color, Color back_color, TextPositioning text_position, float char_offset, + bool visible, FormatSpecified specified) { Line l; // First, format the first line if (start_line != end_line) { // First line - LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, font, color, back_color, specified); + LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, font, color, + back_color, text_position, char_offset, visible, specified); // Format last line - LineTag.FormatText(end_line, 1, end_pos, font, color, back_color, specified); + LineTag.FormatText(end_line, 1, end_pos - 1, font, color, back_color, text_position, char_offset, visible, specified); // Now all the lines inbetween for (int i = start_line.line_no + 1; i < end_line.line_no; i++) { l = GetLine(i); - LineTag.FormatText(l, 1, l.text.Length, font, color, back_color, specified); + LineTag.FormatText(l, 1, l.text.Length, font, color, back_color, text_position, char_offset, visible, specified); } } else { // Special case, single line - LineTag.FormatText(start_line, start_pos, end_pos - start_pos, font, color, back_color, specified); + LineTag.FormatText(start_line, start_pos, end_pos - start_pos, font, color, back_color, + text_position, char_offset, visible, specified); if ((end_pos - start_pos) == 0 && CaretTag.Length != 0) CaretTag = CaretTag.Next; @@ -3582,17 +3771,7 @@ namespace System.Windows.Forms { line = GetLine(line_no); if (line != null) { - switch (line.alignment) { - case HorizontalAlignment.Left: - line.align_shift = 0; - break; - case HorizontalAlignment.Center: - line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2; - break; - case HorizontalAlignment.Right: - line.align_shift = viewport_width - (int)line.widths[line.text.Length] - right_margin; - break; - } + line.CalculateAlignment(); } line_no++; @@ -3623,6 +3802,8 @@ namespace System.Windows.Forms { int new_width; bool changed; int shift; + bool width_changed; + bool height_changed; if (recalc_suspended > 0) { recalc_pending = true; @@ -3641,6 +3822,8 @@ namespace System.Windows.Forms { line_no = start; new_width = 0; shift = this.lines; + width_changed = false; + height_changed = false; if (!optimize) { changed = true; // We always return true if we run non-optimized } else { @@ -3677,17 +3860,10 @@ namespace System.Windows.Forms { } if (line.widths[line.text.Length] > new_width) { - new_width = (int)line.widths[line.text.Length]; + new_width = (int)Math.Ceiling(line.widths[line.text.Length]); } - // Calculate alignment - if (line.alignment != HorizontalAlignment.Left) { - if (line.alignment == HorizontalAlignment.Center) { - line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2; - } else { - line.align_shift = viewport_width - (int)line.widths[line.text.Length] - 1; - } - } + line.CalculateAlignment (); if (multiline) offset += line.height; @@ -3701,22 +3877,22 @@ namespace System.Windows.Forms { if (document_x != new_width) { document_x = new_width; - if (WidthChanged != null) { - WidthChanged(this, null); - } + width_changed = true; } - RecalculateAlignments(); - line = GetLine(lines); if (document_y != line.Y + line.height) { document_y = line.Y + line.height; - if (HeightChanged != null) { - HeightChanged(this, null); - } + height_changed = true; + } + + if (height_changed || width_changed) { + SizeChanged?.Invoke (this, new SizeChangedEventArgs(height_changed)); } + RecalculateAlignments (); + // scan for links and tell us if its all // changed, so we can update everything if (EnableLinks) @@ -3731,13 +3907,15 @@ namespace System.Windows.Forms { } private void owner_HandleCreated(object sender, EventArgs e) { - using (var graphics = owner.CreateGraphics()) + using (var graphics = owner.CreateGraphics()) { + dpi = (graphics.DpiX + graphics.DpiY) / 2; RecalculateDocument(graphics); + } AlignCaret(); } private void owner_VisibleChanged(object sender, EventArgs e) { - if (owner.Visible) { + if (owner.Visible && owner.IsHandleCreated) { using (var graphics = owner.CreateGraphics()) RecalculateDocument(graphics); } @@ -4031,9 +4209,17 @@ namespace System.Windows.Forms { #endregion // Internal Methods #region Events + internal class SizeChangedEventArgs : EventArgs { + public bool HeightChanged { get; } + + public SizeChangedEventArgs (bool HeightChanged) + { + this.HeightChanged = HeightChanged; + } + } + internal event EventHandler CaretMoved; - internal event EventHandler WidthChanged; - internal event EventHandler HeightChanged; + internal event EventHandler<SizeChangedEventArgs> SizeChanged; internal event EventHandler LengthChanged; internal event EventHandler UIASelectionChanged; #endregion // Events @@ -4089,7 +4275,10 @@ namespace System.Windows.Forms { public override SizeF SizeOfPosition (Graphics dc, int pos) { - return picture.Size; + if (Visible) + return picture.Size; + else + return SizeF.Empty; } internal override int MaxHeight () @@ -4099,12 +4288,24 @@ namespace System.Windows.Forms { public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end) { - picture.DrawImage (dc, xoff + Line.widths [start], y, false); + if (Visible) + picture.DrawImage (dc, (xoff + Line.widths [start]), y, false); } public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, string text) { - picture.DrawImage (dc, xoff + + Line.widths [start], y, false); + Draw (dc, color, xoff, y, start, end); + } + + public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, + string text, out Rectangle measuredText, bool measureText) + { + Draw (dc, color, xoff, y, start, end); + if (measureText && Visible) { + measuredText = new Rectangle (Point.Round (new PointF (xoff + Line.widths [start], y)), Size.Round (picture.Size)); + } else { + measuredText = new Rectangle (); + } } public override string Text () diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs index 33eb3c50b99..2bf32495378 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripDropDown.cs @@ -383,26 +383,36 @@ namespace System.Windows.Forms [EditorBrowsable (EditorBrowsableState.Never)] public new void Show () { - Show (Location, DefaultDropDownDirection); + Show (Location); + } + + public void Show (int x, int y) + { + Show (new Point (x, y)); } public void Show (Point screenLocation) { + SetOwnerControl (null); Show (screenLocation, DefaultDropDownDirection); } - + + public void Show (Control control, int x, int y) + { + Show (control, new Point (x, y)); + } + public void Show (Control control, Point position) { - if (control == null) - throw new ArgumentNullException ("control"); - - XplatUI.SetOwner (Handle, control.Handle); - Show (control.PointToScreen (position), DefaultDropDownDirection); + Show (control, position, DefaultDropDownDirection); } - public void Show (int x, int y) + public void Show (Control control, Point position, ToolStripDropDownDirection direction) { - Show (new Point (x, y), DefaultDropDownDirection); + if (control == null) + throw new ArgumentNullException ("control"); + SetOwnerControl (control); + Show (control.PointToScreen (position), direction); } public void Show (Point position, ToolStripDropDownDirection direction) @@ -522,26 +532,17 @@ namespace System.Windows.Forms this.OnOpened (EventArgs.Empty); } - - public void Show (Control control, int x, int y) - { - if (control == null) - throw new ArgumentNullException ("control"); - Show (control, new Point (x, y)); - } - - public void Show (Control control, Point position, ToolStripDropDownDirection direction) - { - if (control == null) - throw new ArgumentNullException ("control"); - - XplatUI.SetOwner (Handle, control.Handle); - Show (control.PointToScreen (position), direction); - } #endregion #region Protected Methods + + protected virtual void SetOwnerControl (Control ownerControl) + { + var ownerControlHandle = (ownerControl == null) ? IntPtr.Zero : ownerControl.Handle; + XplatUI.SetOwner (Handle, ownerControlHandle); + } + protected override AccessibleObject CreateAccessibilityInstance () { return new ToolStripDropDownAccessibleObject (this); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs index 4df33979088..7a60ac82f29 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/ToolStripMenuItem.cs @@ -419,10 +419,8 @@ namespace System.Windows.Forms if (item.Owner == null) return null; - if (item.Owner is ContextMenuStrip) { - Control container = ((ContextMenuStrip)item.Owner).container; - return container == null ? null : container.TopLevelControl; - } + if (item.Owner is ContextMenuStrip ownerContextMenuStrip) + return ownerContextMenuStrip.SourceControl?.TopLevelControl; // MainMenuStrip return item.Owner.TopLevelControl; diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TreeView.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TreeView.cs index 74d77f5f80f..a66f82ccc36 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TreeView.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TreeView.cs @@ -1419,7 +1419,7 @@ namespace System.Windows.Forms { private void Draw (Rectangle clip, Graphics dc) { - dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip); + dc.FillRectangle (BackColorBrush, clip); if (dash == null) CreateDashPen (); @@ -1670,7 +1670,6 @@ namespace System.Windows.Forms { { if (!full_row_select || show_lines) DrawSelectionAndFocus(node, dc, node.Bounds); - Font font = node.NodeFont; if (node.NodeFont == null) @@ -1691,7 +1690,7 @@ namespace System.Windows.Forms { int middle = y + (ActualItemHeight / 2); if (full_row_select && !show_lines) { - Rectangle r = new Rectangle (1, y, ViewportRectangle.Width - 2, ActualItemHeight); + var r = new Rectangle (1, y, ViewportRectangle.Width - 2, ActualItemHeight); DrawSelectionAndFocus (node, dc, r); } @@ -1716,26 +1715,25 @@ namespace System.Windows.Forms { } if (draw_mode != TreeViewDrawMode.Normal) { - dc.FillRectangle (Brushes.White, node.Bounds); - TreeNodeStates tree_node_state = TreeNodeStates.Default;; + dc.FillRectangle (BackColorBrush, node.Bounds); + + var tree_node_state = TreeNodeStates.Default;; if (node.IsSelected) tree_node_state = TreeNodeStates.Selected; if (node.Checked) tree_node_state |= TreeNodeStates.Checked; if (node == focused_node) tree_node_state |= TreeNodeStates.Focused; - Rectangle node_bounds = node.Bounds; - if (draw_mode == TreeViewDrawMode.OwnerDrawText) { - node_bounds.X += 3; - node_bounds.Y += 1; - } else { + + var node_bounds = node.Bounds; + if (draw_mode != TreeViewDrawMode.OwnerDrawText) { node_bounds.X = 0; node_bounds.Width = Width; } - DrawTreeNodeEventArgs e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state); + var e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state); - OnDrawNode (e); + OnDrawNode (e); if (!e.DrawDefault) return; } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources index a4045f284ea..c9eb6898556 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms_test.dll.sources @@ -26,6 +26,7 @@ System.Windows.Forms/Common.cs System.Windows.Forms/CommonDialogsTest.cs System.Windows.Forms/ContainerControlTest.cs System.Windows.Forms/ContextMenuTest.cs +System.Windows.Forms/ContextMenuStripTest.cs System.Windows.Forms/ControlBindingsCollectionTest.cs System.Windows.Forms/ControlBindingsConverterTest.cs System.Windows.Forms/ControlCollectionTest.cs diff --git a/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContextMenuStripTest.cs b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContextMenuStripTest.cs new file mode 100644 index 00000000000..f5f62d6d330 --- /dev/null +++ b/mcs/class/System.Windows.Forms/Test/System.Windows.Forms/ContextMenuStripTest.cs @@ -0,0 +1,166 @@ +// +// ContextMenuTestStrip.cs: Test cases for ContextMenuStrip +// +// Author: +// Nikita Voronchev (nikita.voronchev@ru.axxonsoft.com) +// +// (C) 2020 AxxonSoft (https://www.axxonsoft.com/) +// + +using System; +using System.Drawing; +using System.Windows.Forms; +using NUnit.Framework; + +namespace MonoTests.System.Windows.Forms +{ + // TODO: + // -- Tests around `OwnerItem`. + + [TestFixture] + public class ContextMenuStripTest : TestHelper + { + static TestExtendedForm form; + static Label explicitMenuSrcLabel; + static TestExtendedLabel testExtendedLabel; + static ContextMenuStrip contextMenuStrip; + + static readonly Lazy<Control>[] testCaseExplicitMenuSources = new Lazy<Control>[] { + new Lazy<Control>(() => null), + new Lazy<Control>(() => explicitMenuSrcLabel) + }; // Involve `Lazy` to use `TestCaseSource` attribute. + + static readonly Lazy<ITestExtendedControl>[] testCaseAssociatedControls = new Lazy<ITestExtendedControl>[] { + new Lazy<ITestExtendedControl>(() => form), + new Lazy<ITestExtendedControl>(() => testExtendedLabel) + }; // Involve `Lazy` to use `TestCaseSource` attribute. + + [SetUp] + public void SetUp() + { + form = new TestExtendedForm (); + explicitMenuSrcLabel = new Label (); + testExtendedLabel = new TestExtendedLabel (); + contextMenuStrip = new ContextMenuStrip (); + + form.ShowInTaskbar = false; + form.Controls.Add (explicitMenuSrcLabel); + form.Controls.Add (testExtendedLabel); + } + + [TearDown] + public void TearDown() + { + contextMenuStrip.Close (); + form.Controls.Clear (); + + contextMenuStrip.Dispose (); + testExtendedLabel.Dispose (); + explicitMenuSrcLabel.Dispose (); + form.Dispose (); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest01 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (); + Assert.IsNull (contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest02 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (form, Point.Empty); + Assert.AreEqual (form, contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest03 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (explicitMenuSrcLabel, Point.Empty); + Assert.AreEqual (explicitMenuSrcLabel, contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest04 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (testExtendedLabel, Point.Empty); + Assert.AreEqual (testExtendedLabel, contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource ("testCaseExplicitMenuSources")] + public void DirectShowTest05 (Lazy<Control> explicitMenuSrc) + { + AssingOwner (explicitMenuSrc.Value); + contextMenuStrip.Show (form, Point.Empty); + contextMenuStrip.Close (); + contextMenuStrip.Show (); + Assert.IsNull (contextMenuStrip.SourceControl, "SourceControl"); + } + + [Test, TestCaseSource("testCaseAssociatedControls")] + public void ContextShowTest (Lazy<ITestExtendedControl> associatedControl) + { + bool menuHasBeenOpened = false; + contextMenuStrip.Opened += (sender, args) => { menuHasBeenOpened = true; }; + + var assCtrl = associatedControl.Value; + assCtrl.ContextMenuStrip = contextMenuStrip; + + Assert.IsFalse (menuHasBeenOpened, "menuHasBeenOpened"); + assCtrl.EmulateWmContextMenu (); + Assert.IsTrue (menuHasBeenOpened, "menuHasBeenOpened"); + Assert.AreEqual (assCtrl, contextMenuStrip.SourceControl, "SourceControl"); + + } + + #region Helpers + + private void AssingOwner (Control explicitMenuSrc) + { + if (explicitMenuSrc != null) + explicitMenuSrc.ContextMenuStrip = contextMenuStrip; + } + + public interface ITestExtendedControl + { + void EmulateWmContextMenu (); + ContextMenuStrip ContextMenuStrip { set; } + } + + class TestExtendedForm : Form, ITestExtendedControl + { + public void EmulateWmContextMenu () + { + var m = TestExtendedControlHelper.MakeWmContextMenu (); + WndProc (ref m); + } + } + + class TestExtendedLabel : Label, ITestExtendedControl + { + public void EmulateWmContextMenu () + { + var m = TestExtendedControlHelper.MakeWmContextMenu (); + WndProc (ref m); + } + } + + static class TestExtendedControlHelper + { + public static Message MakeWmContextMenu () + { + return new Message () { + Msg = (int)Msg.WM_CONTEXTMENU, + LParam = IntPtr.Zero + }; + } + } + + #endregion // end of Helpers + } +} diff --git a/mcs/class/corlib/ReferenceSources/Buffer.cs b/mcs/class/corlib/ReferenceSources/Buffer.cs index f89199219b5..5c83291cf5c 100644 --- a/mcs/class/corlib/ReferenceSources/Buffer.cs +++ b/mcs/class/corlib/ReferenceSources/Buffer.cs @@ -86,14 +86,14 @@ namespace System var src = (byte*)source; var dst = (byte*)destination; - while (sourceBytesToCopy > int.MaxValue) { - Memcpy (dst, src, int.MaxValue); - sourceBytesToCopy -= int.MaxValue; - src += int.MaxValue; - dst += int.MaxValue; + while (sourceBytesToCopy > uint.MaxValue) { + Memmove (dst, src, uint.MaxValue); + sourceBytesToCopy -= uint.MaxValue; + src += uint.MaxValue; + dst += uint.MaxValue; } - Memcpy (dst, src, (int) sourceBytesToCopy); + Memmove (dst, src, (uint) sourceBytesToCopy); } [CLSCompliantAttribute (false)] @@ -105,14 +105,14 @@ namespace System var src = (byte*)source; var dst = (byte*)destination; - while (sourceBytesToCopy > int.MaxValue) { - Memcpy (dst, src, int.MaxValue); - sourceBytesToCopy -= int.MaxValue; - src += int.MaxValue; - dst += int.MaxValue; + while (sourceBytesToCopy > uint.MaxValue) { + Memmove (dst, src, uint.MaxValue); + sourceBytesToCopy -= uint.MaxValue; + src += uint.MaxValue; + dst += uint.MaxValue; } - Memcpy (dst, src, (int) sourceBytesToCopy); + Memmove (dst, src, (uint) sourceBytesToCopy); } internal static unsafe void memcpy4 (byte *dest, byte *src, int size) { diff --git a/mcs/class/corlib/Test/System/BufferTest.cs b/mcs/class/corlib/Test/System/BufferTest.cs index 120f75bd435..06ad188180d 100644 --- a/mcs/class/corlib/Test/System/BufferTest.cs +++ b/mcs/class/corlib/Test/System/BufferTest.cs @@ -297,5 +297,27 @@ namespace MonoTests.System { Assert.AreEqual (0xAABB0000, b, "#2"); } } + + [Test] // https://github.com/mono/mono/issues/18516 + public unsafe void MemoryCopy_Overlapped () + { + byte [] buffer = new byte [5]; + for (int i = 0; i < buffer.Length; i++) + buffer [i] = (byte)i; + + int bytesToCopy = buffer.Length - 1; + fixed (byte* pBuffer = buffer) + Buffer.MemoryCopy (pBuffer, pBuffer + 1, buffer.Length - 1, bytesToCopy); + + bool failed = false; + for (int i = 0; i < buffer.Length; i++) + { + byte expectedByte = (byte)(i == 0 ? 0 : i - 1); + if (buffer [i] != expectedByte) + failed = true; + } + + Assert.IsFalse (failed); + } } } diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs index c8494518ad7..1088307b338 100644 --- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs +++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/DebugStore.cs @@ -10,6 +10,7 @@ using Mono.Cecil.Pdb; using Newtonsoft.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Threading; namespace WebAssembly.Net.Debugging { internal class BreakPointRequest { @@ -24,7 +25,9 @@ namespace WebAssembly.Net.Debugging { public static BreakPointRequest Parse (JObject args, DebugStore store) { - if (args == null) + // Events can potentially come out of order, so DebugStore may not be initialized + // The BP being set in these cases are JS ones, which we can safely ignore + if (args == null || store == null) return null; var url = args? ["url"]?.Value<string> (); @@ -492,6 +495,7 @@ namespace WebAssembly.Net.Debugging { } internal class DebugStore { + MonoProxy proxy; List<AssemblyInfo> assemblies = new List<AssemblyInfo> (); HttpClient client = new HttpClient (); @@ -500,7 +504,7 @@ namespace WebAssembly.Net.Debugging { public Task<byte[][]> Data { get; set; } } - public async Task Load (string [] loaded_files) + public async Task Load (SessionId sessionId, string [] loaded_files, CancellationToken token) { static bool MatchPdb (string asm, string pdb) => Path.ChangeExtension (asm, "pdb") == pdb; @@ -525,6 +529,15 @@ namespace WebAssembly.Net.Debugging { }); } catch (Exception e) { Console.WriteLine ($"Failed to read {url} ({e.Message})"); + var o = JObject.FromObject (new { + entry = new { + source = "other", + level = "warning", + text = $"Failed to read {url} ({e.Message})" + } + }); + proxy.SendEvent (sessionId, "Log.entryAdded", o, token); + } } @@ -547,7 +560,7 @@ namespace WebAssembly.Net.Debugging { public AssemblyInfo GetAssemblyByName (string name) => assemblies.FirstOrDefault (a => a.Name.Equals (name, StringComparison.InvariantCultureIgnoreCase)); - /* + /* V8 uses zero based indexing for both line and column. PPDBs uses one based indexing for both line and column. */ @@ -600,7 +613,7 @@ namespace WebAssembly.Net.Debugging { PPDBs uses one based indexing for both line and column. */ static bool Match (SequencePoint sp, int line, int column) - { + { var bp = (line: line + 1, column: column + 1); if (sp.StartLine > bp.line || sp.EndLine < bp.line) diff --git a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs index 9cdb0549002..623cdeb0353 100644 --- a/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs +++ b/sdks/wasm/Mono.WebAssembly.DebuggerProxy/MonoProxy.cs @@ -596,7 +596,7 @@ namespace WebAssembly.Net.Debugging { var the_pdbs = the_value?.ToObject<string[]> (); store = new DebugStore (); - await store.Load(the_pdbs); + await store.Load(sessionId, the_pdbs, token); } async Task RuntimeReady (SessionId sessionId, CancellationToken token) |