From 08d210474dcf15c239160ca885bd7799ac618787 Mon Sep 17 00:00:00 2001 From: dkf Date: Sat, 22 Nov 2008 18:08:51 +0000 Subject: TIP#119 implementation. [Patch 1611359] --- ChangeLog | 327 ++++++++++++++-------------- generic/tkCanvText.c | 298 +++++++++++++++++--------- generic/tkFont.c | 388 ++++++++++++++++++++++++++++++++- generic/tkInt.h | 28 ++- library/prolog.ps | 12 +- macosx/tkMacOSXFont.c | 70 +++++- tests/canvText.test | 581 ++++++++++++++++++++++++-------------------------- unix/tkUnixFont.c | 283 +++++++++++++++++++++++- unix/tkUnixRFont.c | 292 ++++++++++++++++++++++--- win/tkWinFont.c | 303 +++++++++++++++++++++----- 10 files changed, 1922 insertions(+), 660 deletions(-) diff --git a/ChangeLog b/ChangeLog index b753a3b..81b169e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,29 +1,42 @@ -2008-11-22 Pat Thoyts +2008-11-22 Donal K. Fellows + + TIP #119 IMPLEMENTATION + + * generic/tkCanvText.c: Added -angle configuration option to canvas + * generic/tkFont.c: text items. This required reengineering the + * library/prolog.ps: whole text rendering engine to be able to + * macosx/tkMacOSXFont.c: handle an angle! No change to any external + * unix/tkUnixFont.c: API. Note, this feature was originally + * unix/tkUnixRFont.c: approved for Tk 8.5, but it has proved much + * win/tkWinFont.c: harder to implement than originally + * generic/tkInt.h: estimated. [Patch 1611359] + * tests/canvText.test: + +2008-11-22 Pat Thoyts - * test/winDialog.test: [Bug 2307837] avoid some locale-dependent - * win/tkWinTest.c: failures by using id's or an english constraint + * test/winDialog.test: Avoid some locale-dependent failures by using + * win/tkWinTest.c: id's or an english constraint. [Bug 2307837] -2008-11-19 Joe English +2008-11-19 Joe English - * doc/ttk_panedwindow.n: Remove inoperative text - stating that slave windows must be direct children - of the master [Bug 1824996]. + * doc/ttk_panedwindow.n: Remove inoperative text stating that slave + windows must be direct children of the master. [Bug 1824996] 2008-11-19 Jan Nijtmans - * generic/tkImgPhoto.c Minor simplification in fix for [Bug 2312027]: - no need to malloc and copy photo type name because - it is a constant to begin with. - * generic/tkOldConfig.c Convert Tcl_SetResult(......, TCL_DYNAMIC) to - * mac/tkMacOSXWm.c Tcl_SetResult(......, TCL_VOLATILE), in preparation - * unix/tkUnixWm.c for TIP #340 + * generic/tkImgPhoto.c Minor simplification in fix for [Bug 2312027] + no need to malloc and copy photo type name + because it is a constant to begin with. + * generic/tkOldConfig.c Convert Tcl_SetResult(......, TCL_DYNAMIC) to + * mac/tkMacOSXWm.c Tcl_SetResult(......, TCL_VOLATILE), in + * unix/tkUnixWm.c preparation for TIP #340 * unix/tkUnixSend.c * win/tkWinWm.c -2008-11-16 Joe English - - * generic/ttk/ttkWidget.c: Widget self-destruction is - not necessarily an error [Bug 2298720]. +2008-11-16 Joe English + + * generic/ttk/ttkWidget.c: Widget self-destruction is not necessarily + an error. [Bug 2298720] 2008-11-16 Donal K. Fellows @@ -31,17 +44,17 @@ avoid making unwarranted assumptions about how magical it is. Triggered by [Bug 2282861] discussion. -2008-11-14 Pat Thoyts +2008-11-14 Pat Thoyts - * generic/tk.h: The TIP 125 implementation permits the + * generic/tk.h: The TIP 125 implementation permits the * generic/tkFrame.c: [wm manage] command to manage any widget but * macosx/tkMacOSXWm.c: only those with Frame instance data should be * unix/tkUnixWm.c: permitted. We now check for the suitability and * win/tkWinWm.c: raise an error for non-frame widgets. Updated - * test/wm.test: the tests and documentation. See also [Bug - * doc/wm.n: 2239034] + * test/wm.test: the tests and documentation. See also [Bug + * doc/wm.n: 2239034] -2008-11-12 Joe English +2008-11-12 Joe English * generic/ttk/ttkWidget.c: Reworked widget construction and destruction sequence; fixes [Bug 2207435] and several other problems @@ -50,42 +63,44 @@ initializeProc being called earlier in the construction sequence now. * tests/ttk/ttk.test: Updated test suite. -2008-11-12 Pat Thoyts +2008-11-12 Pat Thoyts * library/text.tcl: Handle windows with funky names by avoiding use of * test/text.test: the window path for anchors. [Bug 1777362] 2008-11-11 Jan Nijtmans - * generic/tkImgPhoto.c Fix [Bug 2265860] new test failures + * generic/tkImgPhoto.c Fix [Bug 2265860] new test failures -2008-11-11 Joe English +2008-11-11 Joe English * generic/ttk/ttkWidget.c(BeginDrawing): Don't crash when application uses nondefault visual. [Bug 2264732] 2008-11-11 Jan Nijtmans - * win/tcl.m4: reverted change from 2008-11-06 (was under the impression - that "-Wno-implicit-int" added an extra warning) - * win/configure (regenerated) - * unix/tcl.m4: Use -O2 as gcc optimization compiler flag, and get - rid of -Wno-implicit-int for UNIX + * win/tcl.m4: Reverted change from 2008-11-06 (was under the + impression that "-Wno-implicit-int" added an extra + warning) + * win/configure (regenerated) + * unix/tcl.m4: Use -O2 as gcc optimization compiler flag, and get + rid of -Wno-implicit-int for UNIX * unix/configure (regenerated) - * generic/tk.decls modify Tk_Create(Old)ImageType signature, relaxing - * generic/tk.h the constraint that every Tk_ImageType can only - * generic/tkImage.c be passed to this function once. This allows - * generic/tkImgBmap.c tkImg to be loaded in multiple interpreters + * generic/tk.decls Modify Tk_Create(Old)ImageType signature, + * generic/tk.h relaxing the constraint that every Tk_ImageType + * generic/tkImage.c can only be passed to this function once. This + * generic/tkImgBmap.c lets tkImg be loaded in multiple interpreters * generic/tkImgPhoto.c in a thread-enabled build of Tk. [Bug 2312027] - * generic/tkTest.c This CONSTification complies with TIP #27. It is - * doc/CrtImgType.3 binary compatible with the old interface, but not - fully source compatible (although tkImg does not suffer). + * generic/tkTest.c This CONSTification complies with TIP #27. It + * doc/CrtImgType.3 is binary compatible with the old interface, + but not fully source compatible (although tkImg + does not suffer). * generic/tkDecls.h (regenerated) *** POTENTIAL INCOMPATIBILITY *** -2008-11-09 Joe English +2008-11-09 Joe English * generic/ttk/ttkWidget.c: Remove unnecessary casts. @@ -101,16 +116,16 @@ 2008-11-09 Jan Nijtmans - * generic/tkCanvas.c: Make all Tk_CustomOption tables const and - * generic/tkCanvBmap.c: remove unnecessary type cast. + * generic/tkCanvas.c: Make all Tk_CustomOption tables const and + * generic/tkCanvBmap.c: remove unnecessary type cast. * generic/tkCanvImg.c: * generic/tkCanvPoly.c: * generic/tkCanvText.c: * generic/tkCanvWind.c: * generic/tkRectOval.c: * generic/tkScrollbar.c: - * generic/tk.decls: Two more (hopefully the last) signature - * generic/tkInt.h: changes in Tk_CreateSmoothMethod and + * generic/tk.decls: Two more (hopefully the last) signature + * generic/tkInt.h: changes in Tk_CreateSmoothMethod and * generic/tkCanvLine.c: Tk_CreatePhotoImageFormat * generic/tkCanvUtil.c: * generic/tkImgPhoto.c: @@ -150,10 +165,10 @@ 2008-11-03 Jan Nijtmans * generic/ttk/ttkEntry.c: Fix warning: unused variable `currentValue' - * generic/tkOldTest.c: Fix warning: assignment discards qualifiers - * win/tkWinTest.c: from pointer target type + * generic/tkOldTest.c: Fix warning: assignment discards qualifiers + * win/tkWinTest.c: from pointer target type -2008-11-03 Pat Thoyts +2008-11-03 Pat Thoyts * tests/winClipboard.test: testclipboard no longer returns strings with embedded \r but now returns Tcl strings @@ -163,7 +178,7 @@ 2008-11-02 Jan Nijtmans - * generic/tkFont.h: More internal -Wwrite-strings warning fixes + * generic/tkFont.h: More internal -Wwrite-strings warning fixes * generic/tkFont.c * generic/ttk/ttkTheme.h * generic/ttk/ttkDefaultTheme.c @@ -182,7 +197,7 @@ whether they support finding and moving individual coordinates. * doc/canvas.n, tests/canvas.test: Docs 'n' tests. -2008-11-01 Pat Thoyts +2008-11-01 Pat Thoyts * generic/ttk/ttkEntry.c: Implemented the themed spinbox * library/ttk/altTheme.tcl: widget. @@ -199,13 +214,13 @@ * doc/ttk_spinbox.n: * tests/ttk/spinbox.test: -2008-10-31 Joe English +2008-10-31 Joe English * generic/widget.c: Temporary workaround for [Bug 2207435] 2008-10-30 Jan Nijtmans - * generic/tkAtom.c: more internal -Wwrite-strings warning fixes + * generic/tkAtom.c: more internal -Wwrite-strings warning fixes * generic/tkBusy.c * generic/tkButton.c * generic/tkCanvPoly.c @@ -222,26 +237,26 @@ * generic/tkText.c * generic/tkTextImage.c -2008-10-30 Don Porter +2008-10-30 Don Porter * tests/unixSelect.test: Revise the unixSelect-1.* tests so that they test the ability of Tk's selection mechanism to faithfully pass valid Tcl values without corruption, and stop testing details of - Tcl's internal encoding scheme. With this change, the Tk test suite + Tcl's internal encoding scheme. With this change, the Tk test suite no longer uses the identity encoding or [string bytelength]. 2008-10-30 Jan Nijtmans - * generic/tk.h: CONSTify return value of - * generic/tkInt.h Tk_OptionPrintProc, and customPtr - * generic/tk.decls field of Tk_ConfigSpec. - * generic/tkCanvArc.c See [Bug 2190619]: Warnings due to - * generic/tkCanvLine.c Tk_SmoothMethod name constness change + * generic/tk.h: CONSTify return value of + * generic/tkInt.h Tk_OptionPrintProc, and customPtr + * generic/tk.decls field of Tk_ConfigSpec. + * generic/tkCanvArc.c See [Bug 2190619]: Warnings due to + * generic/tkCanvLine.c Tk_SmoothMethod name constness change * generic/tkCanvUtil.c * generic/tkUtil.c - * generic/tkDecls.h: (regenerated) + * generic/tkDecls.h: (regenerated) -2008-10-29 Joe English +2008-10-29 Joe English * generic/tkAtom.c(Tk_GetAtomName): Remove incorrect 'const' qualifier. Remove useless 'register' declarations too, while we're at it. @@ -266,7 +281,7 @@ * generic/tkWindow.c: * win/tkWinTest.c: fix compilation under mingw32 -2008-10-28 Joe English +2008-10-28 Joe English * library/ttk/cursors.tcl, library/ttk/combobox.tcl, library/ttk/entry.tcl, library/ttk/paned.tcl, library/ttk/sizegrip.tcl, @@ -275,27 +290,27 @@ Expanded set of symbolic cursors. Use correct cursor for ttk::entry and ttk::combobox widgets [Bug 1534835] -2008-10-28 Don Porter +2008-10-28 Don Porter * win/tkWinTest.c: Revise [testclipboard] to form that * tests/winClipboard.test: handles encodings. [Bug 2191960] * tests/constraints.tcl: [tcltest::bytestring] no longer used. -2008-10-24 Joe English +2008-10-24 Joe English - * tests/ttk/ttk.test: Disable test ttk-6.3, it's not - applicable [Bug 2175411]. + * tests/ttk/ttk.test: Disable test ttk-6.3, it's not applicable. [Bug + 2175411] - * generic/ttk/ttkTheme.c: Use different Tcl_AssocData key - so the tile extension can be loaded into an 8.6 interp, - in the off-chance that anyone wants to do this. + * generic/ttk/ttkTheme.c: Use different Tcl_AssocData key so the tile + extension can be loaded into an 8.6 interp, in the off-chance that + anyone wants to do this. 2008-10-24 Donal K. Fellows * generic/tkCanvUtil.c (TkSmoothPrintProc): Corrected 'const'ness to quell warning. [Bug 2190619] -2008-10-23 Don Porter +2008-10-23 Don Porter * README: Bump version number to 8.6a4 * generic/tk.h: @@ -309,11 +324,11 @@ 2008-10-22 Jan Nijtmans - * generic/tk.h: CONST -> const and white-spacing + * generic/tk.h: CONST -> const and white-spacing * generic/tk.decls * generic/tkInt.decls - * generic/tkDecls.h: (regenerated) - * generic/tkIntDecls.h: (regenerated) + * generic/tkDecls.h: (regenerated) + * generic/tkIntDecls.h: (regenerated) * generic/tkIntPlatDecls.h: (regenerated) * generic/tkIntXlibDecls.h: (regenerated) * generic/tkPlatDecls.h: (regenerated) @@ -334,7 +349,7 @@ * generic/tkBusy.c, doc/busy.n, tests/busy.test: Implementation of the [tk busy] command. [Patch 1997907] -2008-10-18 Pat Thoyts +2008-10-18 Pat Thoyts * win/tkWinFont.c: [Bug 1825353] To fix a problem with tiny fonts on Russian versions of Windows we will avoid removing the internal @@ -342,10 +357,10 @@ 2008-10-15 Jan Nijtmans - * generic/tk.h: Add "const" to many internal const tables, so - * generic/tkBind.c: those will be put by the C-compiler in the - * generic/tkButton.c: TEXT segment instead of the DATA segment. - * generic/tkCanvas.c: This makes those tables as being shareable in + * generic/tk.h: Add "const" to many internal const tables, so + * generic/tkBind.c: those will be put by the C-compiler in the + * generic/tkButton.c: TEXT segment instead of the DATA segment. + * generic/tkCanvas.c: This makes those tables as being shareable in * generic/tkClipboard.c: shared libraries. * generic/tkCmds.c: * generic/tkConsole.c: @@ -390,17 +405,17 @@ * win/tkWinWm.c: * xlib/xcolors.c: -2008-10-17 Pat Thoyts +2008-10-17 Pat Thoyts * library/ttk/scale.tcl: Implemented keyboard bindings for ttk::scale 2008-10-15 Jan Nijtmans - * generic/tkInt.h: Add "const" to many internal const tables, so - * generic/tk3d.c: those will be put by the C-compiler in the - * generic/tkBitmap.c: TEXT segment instead of the DATA segment. - * generic/tkColor.c: This makes those tables as being shareable in - * generic/tkConfig.c: shared libraries. + * generic/tkInt.h: Add "const" to many internal const tables, so + * generic/tk3d.c: those will be put by the C-compiler in the + * generic/tkBitmap.c: TEXT segment instead of the DATA segment. + * generic/tkColor.c: This makes those tables as being shareable in + * generic/tkConfig.c: shared libraries. * generic/tkCursor.c: * generic/tkFont.c: * generic/tkObj.c: @@ -418,13 +433,13 @@ * generic/tkCanvas.c (CanvasWidgetCmd): Corrected result generation. -2008-10-10 Don Porter +2008-10-10 Don Porter *** 8.6a3 TAGGED FOR RELEASE *** * changes: Updates for 8.6a3 release. -2008-10-09 Don Porter +2008-10-09 Don Porter * generic/tkListbox.c: Make literal return values consistent with those generated by Tcl_PrintDouble(). @@ -438,7 +453,7 @@ * unix/tcl.m4: Fix for bug [2073255] * unix/configure: regenerated -2008-10-08 Don Porter +2008-10-08 Don Porter * tests/textDisp.test (textDisp-16.34): Update test that tested string equality of double values based on an assumption of tcl_precision==12. @@ -454,9 +469,9 @@ * unix/tkUnixWm.c: Restored consistency of error messages from * macosx/tkMacOSXWm.c: [wm iconphoto] with the test suite and across - * tests/unixWm.test: all platforms. [Bug 2021443] + * tests/unixWm.test: all platforms. [Bug 2021443] -2008-10-07 Pat Thoyts +2008-10-07 Pat Thoyts * tests/canvImg.test: Removed dependency on precision in results * tests/canvRect.test: @@ -468,7 +483,7 @@ * tests/winWm.test: Fixed incorrect error strings * tests/wm.test: -2008-10-06 Pat Thoyts +2008-10-06 Pat Thoyts * tests/winDialog.test: Fixed tests for Vista+ * win/tkWinWm.c: corrected some errors from the previous commit @@ -538,7 +553,7 @@ * doc/menu.n: Fix typo in docs. [Bug 2098425] -2008-09-03 Don Porter +2008-09-03 Don Porter * generic/tk.h: Dropped use of _ANSI_ARGS_ macro to preserve * generic/tkSelect.h: Tk's TCL_NO_DEPRECATED build. @@ -559,9 +574,9 @@ * tests/winMsbox.test: * tests/winWm.test: -2008-08-28 Don Porter +2008-08-28 Don Porter - * unix/tkConfig.sh.in: Added @XFT_LIBS@ to the definition of TK_LIBS + * unix/tkConfig.sh.in: Added @XFT_LIBS@ to the definition of TK_LIBS to avoid link failures when a "big wish" program links against a --disable-shared build of libtk. (Discovered building expectTk.) @@ -636,7 +651,7 @@ the interaction with the script level) and the photo instances (which handle display). -2008-08-22 Don Porter +2008-08-22 Don Porter *** 8.6a2 TAGGED FOR RELEASE *** @@ -682,7 +697,7 @@ * win/tkWinWindow.c: Remove TkpWindowWasRecentlyDeleted. * tests/id.test: Remove this unnecessary test. -2008-08-19 Joe English +2008-08-19 Joe English * generic/ttk/ttkScroll.c: Don't use sprintf "%g" to format floating point numbers in -[xy]scrollcommand callbacks or [xy]view methods. @@ -738,7 +753,7 @@ * unix/tcl.m4 (SC_PATH_X): Check for libX11.dylib in addition to libX11.so et al. - * unix/configure: autoconf-2.59 + * unix/configure: autoconf-2.59 2008-08-12 Ania Pawelczyk @@ -747,7 +762,7 @@ * tests/embed.test: * tests/main.test: -2008-08-12 Don Porter +2008-08-12 Don Porter * README: Bump version number to 8.6a2 * generic/tk.h: @@ -774,7 +789,7 @@ * tests/config.test: * tests/canvas.test: -2008-08-05 Joe English +2008-08-05 Joe English * generic/tk.h, generic/tkEvent.c: Fix for [Bug 2010422] "no event type or button # or keysym while executing "bind Listbox @@ -787,12 +802,12 @@ * tests/get.test: * tests/text.test: Update to tcltest2; report: 33.11 fails -2008-08-01 Pat Thoyts +2008-08-01 Pat Thoyts * win/tkWinWm.c: Check wmPtr is valid in TopLevelReqProc to fix * tests/wm.test: [Bug 2028703] -2008-07-31 Don Porter +2008-07-31 Don Porter * generic/tk.h: Added missing EXTERN for the Tcl_PkgInitStubsCheck declaration to fix inability to embed non-stub-enabled Tk on Windows. @@ -807,12 +822,12 @@ * tests/cursor.test: Update to tcltest2 * tests/message.test: -2008-07-26 Pat Thoyts +2008-07-26 Pat Thoyts * doc/options.n: Direct to the font manual for -font. [Bug 1686012] * tests/constraints.tcl: Add a nonwin contraint. - * tests/listbox.test: Conform to testing policy. [Bug 2024753] + * tests/listbox.test: Conform to testing policy. [Bug 2024753] * win/tkWinWm.c: Check that the parent has been mapped before * tests/wm.test: calling RemapWindows. [Bug 2009788] @@ -849,11 +864,11 @@ * macosx/tkMacOSXHLEvents.c: Factor out common code; formatting. -2008-07-08 Pat Thoyts +2008-07-08 Pat Thoyts * doc/*.n: Fixed broken line endings from last doc commit. -2008-07-04 Joe English +2008-07-04 Joe English * generic/ttk/ttkDefaultTheme.c, generic/ttk/ttkClamTheme.c, * generic/ttk/ttkClassicTheme.c, generic/ttk/ttkElements.c: Audit: @@ -870,18 +885,18 @@ * doc/*.1, doc/*.3, doc/*.n: Remove out of date changebars, make formatting of typedefs consistent, other small changes. -2008-06-25 Don Porter +2008-06-25 Don Porter *** 8.6a1 TAGGED FOR RELEASE *** * changes: Updates for 8.6a1 release. -2008-06-24 Pat Thoyts +2008-06-24 Pat Thoyts * library/demos/ttkpane.tcl: Work around missing timezones * doc/text.n: Fix documentation of text tag options. [Bug 1997293] -2008-06-19 Don Porter +2008-06-19 Don Porter * changes: Updates for 8.6a1 release. @@ -925,7 +940,7 @@ incorrect conversion to points of font sizes already in points; factor out retrieval of font family name from font family ID. -2008-06-13 Jeff Hobbs +2008-06-13 Jeff Hobbs * win/configure, win/configure.in (TK_WIN_VERSION): Fix handling of interim a/b versioning for manifest usage. @@ -962,7 +977,7 @@ * macosx/Wish.xcode/default.pbxuser: * macosx/README: Document new build configs. -2008-06-10 Joe English +2008-06-10 Joe English * unix/tkUnixKey.c: Use Xutf8LookupString if available. This should fix problems (like [Bug 1908443]) where Xlib's idea of the system @@ -974,12 +989,12 @@ * macosx/README: debug configs with gcov; update to Xcode 3.1. -2008-05-27 Pat Thoyts +2008-05-27 Pat Thoyts * generic/ttk/ttkTheme.c: [ttk::style theme use] without an argument * doc/ttk_style.n: now returns the current theme. -2008-05-23 Joe English +2008-05-23 Joe English * doc/ttk_treeview.n, generic/ttk/ttkTreeview.c, * generic/ttk/ttkTagSet.c, generic/ttk/ttkLayout.c, @@ -997,16 +1012,16 @@ Don't need separate 'Item', 'Cell', and 'Row' style settings anymore, only the base "Treeview" style is used. -2008-05-23 Joe English +2008-05-23 Joe English * generic/ttk/ttkLabel.c: Avoid passing width or height <= 0 to Tk_RedrawImage, as this leads to a panic on Windows. [Bug 1967576] -2008-05-16 Pat Thoyts +2008-05-16 Pat Thoyts * library/ttk/xpTheme.tcl: Add correct border to combobox on Vista -2008-05-15 Pat Thoyts +2008-05-15 Pat Thoyts * win/makefile.vc: We should use the thread allocator for threaded * win/rules.vc: builds. Added 'tclalloc' option to disable. @@ -1017,22 +1032,22 @@ (DisplayPanedWindow): Ensure that a zero width never gets fed to the underlying window system. [Bug 1639824] -2008-05-13 Pat Thoyts +2008-05-13 Pat Thoyts * library/console.tcl: Support pixel sized font in +/- keybinding. * tests/listbox.test: -activestyle default is underline on windows. * tests/winDialog.test: Fixed hanging tk_chooseColor tests. -2008-05-11 Pat Thoyts +2008-05-11 Pat Thoyts * library/tk.tcl: Support for ttk widgets in AmpWidget * doc/button.n: Note negative widths for button. [Patch 1883418] -2008-05-09 Pat Thoyts +2008-05-09 Pat Thoyts * doc/ttk_*: 'identify' widget command is on all ttk widgets. -2008-05-04 Joe English +2008-05-04 Joe English * macosx/ttkMacOSAquaTheme.c: "default" and "focus" adornments should not be disjoint [Bug 1942785] @@ -1045,12 +1060,12 @@ files allow building things that link against Tcl with really ancient compilers still; the requirement is just when building Tcl itself.) -2008-04-25 Joe English +2008-04-25 Joe English * library/ttk/treeview.tcl: BUGFIX: [$tv selection] takes a list of items, not a single item. [Bug 1951733] -2008-04-20 Pat Thoyts +2008-04-20 Pat Thoyts * win/makefile.vc: Include ws2_32 in the link list. [Bug 1900872] * doc/menu.n: Minor change regarding the system menu. [Bug 1887169] @@ -1061,7 +1076,7 @@ * doc/text.n: Correct description of when -relief option is ignored on a tag. Thanks to emiliano for spotting. -2008-04-17 Don Porter +2008-04-17 Don Porter * generic/tkCanvas.c: Fix logic that determines when canvas item event should fire. Thanks to Sebastian Wangnick. [Bug 1327482] @@ -1072,7 +1087,7 @@ * generic/tkWindow.c (Initialize): and export only a module-scope pointer to to the main stubs table (for package init). [Patch 1938497] -2008-04-14 Pat Thoyts +2008-04-14 Pat Thoyts * win/tkWinDialog.c: Fix [tk_chooseColor -title]. [Bug 1941740] * win/tkWinTest.c: Added parent to testgetwininfo @@ -1082,9 +1097,9 @@ * generic/tkImgGIF.c: Let the GIF writer use a real LZW compressor. -2008-04-08 Pat Thoyts +2008-04-08 Pat Thoyts - * win/ttkWinXpTheme.c: Provide a visual-styles API element engine + * win/ttkWinXpTheme.c: Provide a visual-styles API element engine * tests/ttk/vsapi.test: to permit scripts to create any available * doc/ttk_vsapi.n: windows xp/vista element. Plus basic tests. @@ -1096,27 +1111,27 @@ * generic/tkIntXlibDecls.h: * generic/tkPlatDecls.h: -2008-04-08 Kevin Kenny +2008-04-08 Kevin Kenny - * tkWinEmbed.c: Removed #if 0 code. Trust the revision control + * tkWinEmbed.c: Removed #if 0 code. Trust the revision control system, if you need it again, you can find it. - * tkWinSend.c: Added conditional compilation to silence several + * tkWinSend.c: Added conditional compilation to silence several compiler warnings. -2008-04-07 Jeff Hobbs +2008-04-07 Jeff Hobbs * generic/tkWindow.c (Initialize): Fix double-free on Tk_ParseArgv * tests/main.test (main-3.*): error. [Bug 1937135] * generic/tkArgv.c: Fix -help mem explosion. [Bug 1936238] (kenny) -2008-04-04 Pat Thoyts +2008-04-04 Pat Thoyts * library/ttk/sizegrip.tcl: Don't resize if the toplevel is not resizable or the sizegrip has been disabled. -2008-04-03 Pat Thoyts +2008-04-03 Pat Thoyts * win/makefile.vc: Fixed stubs usage * library/ttk/xpTheme.tcl: fix the colour of labelframe in xp @@ -1146,7 +1161,7 @@ * unix/configure: autoconf-2.59 -2008-04-01 Don Porter +2008-04-01 Don Porter * generic/tkStubLib.c (Tk_InitStubs): Added missing error * generic/tkWindow.c (Tk_PkgInitStubsCheck): message and removed @@ -1181,7 +1196,7 @@ * generic/tkIntXlibDecls.h: * generic/tkPlatDecls.h: -2008-03-28 Don Porter +2008-03-28 Don Porter *** 8.5.2 TAGGED FOR RELEASE *** @@ -1197,7 +1212,7 @@ * changes: Updates for 8.5.2 release. -2008-03-27 Jeff Hobbs +2008-03-27 Jeff Hobbs * library/safetk.tcl (::safe::tkInterpInit): Make sure tk_library and its subdirs (eg, ttk) are on the "safe" access path. @@ -1216,20 +1231,20 @@ * generic/ttk/ttkDecls.h: Fix incorrect number of arguments in Ttk_InitStubs macro definition. -2008-03-26 Don Porter +2008-03-26 Don Porter * changes: Updates for 8.5.2 release. * unix/tkUnixCursor.c: Stop crash in [. configure -cursor] on X11. Thanks to emiliano gavilán. [Bug 1922466] -2008-03-26 Joe English +2008-03-26 Joe English * generic/tkInt.h, generic/tkEvent.c, unix/tkUnixEvent.c, * unix/tkUnixKey.c: XIM reorganization and cleanup; see [Patch 1919791] for details. -2008-03-21 Joe English +2008-03-21 Joe English * generic/tk.decls, generic/ttk/ttkStubLib.c, unix/Makefile.in: Keep ttkStubLib.o in libtkstub instead of libtk. [Bug 1920030] @@ -1244,7 +1259,7 @@ * doc/GetClrmap.3: Documented Tk_PreserveColormap. [Bug 220809] -2008-03-17 Joe English +2008-03-17 Joe English * unix/Makefile.in, win/Makefile.in, win/makefile.vc: Put ttkStubLib.o in libtkstub instead of libtk. [Bug 1863007] @@ -1260,7 +1275,7 @@ * unix/tcl.m4: for lib paths in tkConfig.sh. [Bug 1913622] * unix/configure: autoconf-2.59 -2008-03-13 Don Porter +2008-03-13 Don Porter * changes: Updates for 8.5.2 release. @@ -1270,7 +1285,7 @@ * macosx/Wish.xcodeproj/default.pbxuser: CODE_SIGN_IDENTITY and * macosx/Wish-Common.xcconfig: 'xcodebuild install'. -2008-03-12 Joe English +2008-03-12 Joe English * unix/tkUnixRFont.c: Try a fallback font if XftFontOpenPattern() fails in GetFont (workaround for [Bug 1090382]). @@ -1298,7 +1313,7 @@ * unix/Makefile.in (install-strip): Strip non-global symbols from dynamic library. -2008-03-10 Don Porter +2008-03-10 Don Porter * changes: Updates for 8.5.2 release. @@ -1306,14 +1321,14 @@ * doc/colors.n: Reworked to produce nicer HTML output. -2008-03-06 Joe English +2008-03-06 Joe English * doc/ttk_notebook.n: Move "TAB IDENTIFIERS" section above "WIDGET COMMAND" section. [Bug 1882011] -2008-02-29 Pat Thoyts +2008-02-29 Pat Thoyts - * library/demos/widget: Added a Knight's tour canvas demo. + * library/demos/widget: Added a Knight's tour canvas demo. * library/demos/knightstour.tcl: 2008-02-27 Daniel Steffen @@ -1321,14 +1336,14 @@ * macosx/tkMacOSXDraw.c: Workaround leak in Carbon SetPortPenPixPat() API [Bug 1863346]; avoid repeated PixPat allocation/deallocation. -2008-02-23 Joe English +2008-02-23 Joe English * library/ttk/combobox.tcl, doc/ttk_combobox.n, * tests/ttk/combobox.test: Arrange to deliver <> event after listbox is unposted, as intended [Bug 1890211]. Clarified documentation. -2008-02-23 Joe English +2008-02-23 Joe English * generic/ttk/ttkPanedWindow.c: Don't enforce minimum sash thickness of 5 pixels, just use 5 as a default. [FR 1898288] @@ -1341,7 +1356,7 @@ * doc/ttk_scale.n (new file): Added basic documentation. [Bug 1881925] -2008-02-04 Don Porter +2008-02-04 Don Porter *** 8.5.1 TAGGED FOR RELEASE *** @@ -1362,14 +1377,14 @@ 2008-02-02 Daniel Steffen * macosx/Wish-Info.plist.in: Add CFBundleLocalizations key, listing - * unix/configure.in (Darwin): all library/msgs locales. + * unix/configure.in (Darwin): all library/msgs locales. * unix/configure.in (Darwin): Correct Info.plist year substitution in non-framework builds. * unix/configure: autoconf-2.59 -2008-02-01 Don Porter +2008-02-01 Don Porter * changes: Updates for 8.5.1 release. @@ -1378,7 +1393,7 @@ * generic/tkImgGIF.c: Fixed a buffer overflow (CVE-2008-0553). * tests/imgPhoto.test: Added a test for the above. -2008-01-31 Jeff Hobbs +2008-01-31 Jeff Hobbs * library/msgbox.tcl (::tk::MessageBox): Don't use ttk::label in low depth/aqua fallback, as it doesn't support -bitmap. @@ -1396,7 +1411,7 @@ * doc/canvas.n, doc/listbox.n, doc/message.n: Fix erroneous listing of "standard" options. [Bug 1882495] -2008-01-29 Joe English +2008-01-29 Joe English * library/treeview.tcl: Fix bug in Shift-ButtonPress-1 binding (error if no current focus item; reported on c.l.t.) @@ -1407,17 +1422,17 @@ Ttk manual pages so that they are documented in the correct location. [Bug 1876493] -2008-01-28 Joe English +2008-01-28 Joe English * unix/tkUnixRFont.c: Re-fix strict-aliasing warnings reintroduced by last patch. -2008-01-27 Joe English +2008-01-27 Joe English * generic/ttk/ttkNotebook.c: Make sure to schedule a redisplay when adding and/or hiding tabs. [Bug 1878298] -2008-01-27 Joe English +2008-01-27 Joe English * unix/tkUnixRFont.c: Merged common code from InitFont() and TkpGetFontAttrsForChar(), factored into GetTkFontAttributes() and @@ -1426,33 +1441,33 @@ TkFontAttributes.family member is a Tk_Uid, as specified. Use FcTypeDouble for XFT_SIZE attribute. Finally: fix [Bug 1835848] -2008-01-25 Don Porter +2008-01-25 Don Porter * changes: Updates for 8.5.1 release. -2008-01-08 Joe English +2008-01-08 Joe English * generic/ttk/ttkFrame.c: BUGFIX: fix crash in [ttk::labelframe] when -style option specified. [Bug 1867122] -2008-01-08 Joe English +2008-01-08 Joe English * win/ttkWinTheme.c: Add tristate support to checkbuttons and radiobuttons. [Bug 1865898] Fix check and radio indicator size. [Bug 1679067] -2008-01-06 Joe English +2008-01-06 Joe English * generic/ttk/ttkWidget.c, generic/ttk/ttkWidget.h: Call Tk_MakeWindowExist() in widget constructor. Removed now-unnecessary initial ConfigureNotify processing. -2008-01-06 Joe English +2008-01-06 Joe English * library/ttk/treeview.tcl, library/ttk/utils.tcl: Fix MouseWheel bindings for ttk::treeview widget. [Bugs 1442006, 1821939, 1862692] -2008-01-02 Don Porter +2008-01-02 Don Porter * generic/tk.h: Bump version number to 8.5.1b1 to distinguish * library/tk.tcl: CVS development snapshots from the 8.5.0 and diff --git a/generic/tkCanvText.c b/generic/tkCanvText.c index efa2b70..474ed25 100644 --- a/generic/tkCanvText.c +++ b/generic/tkCanvText.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvText.c,v 1.32 2008/11/09 20:51:28 nijtmans Exp $ + * RCS: @(#) $Id: tkCanvText.c,v 1.33 2008/11/22 18:08:51 dkf Exp $ */ #include @@ -57,6 +57,8 @@ typedef struct TextItem { * means no word-wrap. */ int underline; /* Index of character to put underline beneath * or -1 for no underlining. */ + double angle; /* What angle, in degrees, to draw the text + * at. */ /* * Fields whose values are derived from the current values of the @@ -66,18 +68,18 @@ typedef struct TextItem { int numChars; /* Length of text in characters. */ int numBytes; /* Length of text in bytes. */ Tk_TextLayout textLayout; /* Cached text layout information. */ - int leftEdge; /* Pixel location of the left edge of the text - * item; where the left border of the text - * layout is drawn. */ - int rightEdge; /* Pixel just to right of right edge of area - * of text item. Used for selecting up to end - * of line. */ + int actualWidth; /* Width of text as computed. Used to make + * selections of wrapped text display + * right. */ + double drawOrigin[2]; /* Where we start drawing from. */ GC gc; /* Graphics context for drawing text. */ GC selTextGC; /* Graphics context for selected text. */ GC cursorOffGC; /* If not None, this gives a graphics context * to use to draw the insertion cursor when * it's off. Used if the selection and * insertion cursor colors are the same. */ + double sine; /* Sine of angle field. */ + double cosine; /* Cosine of angle field. */ } TextItem; /* @@ -101,6 +103,8 @@ static Tk_ConfigSpec configSpecs[] = { NULL, Tk_Offset(TextItem, activeStipple), TK_CONFIG_NULL_OK}, {TK_CONFIG_ANCHOR, "-anchor", NULL, NULL, "center", Tk_Offset(TextItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_DOUBLE, "-angle", NULL, NULL, + "0.0", Tk_Offset(TextItem, angle), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_COLOR, "-disabledfill", NULL, NULL, NULL, Tk_Offset(TextItem, disabledColor), TK_CONFIG_NULL_OK}, {TK_CONFIG_BITMAP, "-disabledstipple", NULL, NULL, @@ -199,6 +203,8 @@ Tk_ItemType tkTextType = { TextDeleteChars, /* dTextProc */ NULL, /* nextPtr */ }; + +#define ROUND(d) ((int) floor((d) + 0.5)) /* *-------------------------------------------------------------- @@ -258,15 +264,18 @@ CreateText( textPtr->text = NULL; textPtr->width = 0; textPtr->underline = -1; + textPtr->angle = 0.0; textPtr->numChars = 0; textPtr->numBytes = 0; textPtr->textLayout = NULL; - textPtr->leftEdge = 0; - textPtr->rightEdge = 0; + textPtr->actualWidth = 0; + textPtr->drawOrigin[0] = textPtr->drawOrigin[1] = 0.0; textPtr->gc = None; textPtr->selTextGC = None; textPtr->cursorOffGC = None; + textPtr->sine = 0.0; + textPtr->cosine = 1.0; /* * Process the arguments to fill in the item record. Only 1 (list) or 2 (x @@ -325,14 +334,14 @@ TextCoords( if (objc == 0) { Tcl_Obj *obj = Tcl_NewObj(); - Tcl_Obj *subobj = Tcl_NewDoubleObj(textPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); subobj = Tcl_NewDoubleObj(textPtr->y); Tcl_ListObjAppendElement(interp, obj, subobj); Tcl_SetObjResult(interp, obj); } else if (objc < 3) { - if (objc==1) { + if (objc == 1) { if (Tcl_ListObjGetElements(interp, objv[0], &objc, (Tcl_Obj ***) &objv) != TCL_OK) { return TCL_ERROR; @@ -415,24 +424,24 @@ ConfigureText( itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; } - if(state == TK_STATE_NULL) { + if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; } color = textPtr->color; stipple = textPtr->stipple; if (Canvas(canvas)->currentItemPtr == itemPtr) { - if (textPtr->activeColor!=NULL) { + if (textPtr->activeColor != NULL) { color = textPtr->activeColor; } - if (textPtr->activeStipple!=None) { + if (textPtr->activeStipple != None) { stipple = textPtr->activeStipple; } - } else if (state==TK_STATE_DISABLED) { - if (textPtr->disabledColor!=NULL) { + } else if (state == TK_STATE_DISABLED) { + if (textPtr->disabledColor != NULL) { color = textPtr->disabledColor; } - if (textPtr->disabledStipple!=None) { + if (textPtr->disabledStipple != None) { stipple = textPtr->disabledStipple; } } @@ -513,6 +522,22 @@ ConfigureText( textPtr->insertPos = textPtr->numChars; } + /* + * Restrict so that 0.0 <= angle < 360.0, and then recompute the cached + * sine and cosine of the angle. Note that fmod() can produce negative + * results, and we try to avoid negative zero as well. + */ + + textPtr->angle = fmod(textPtr->angle, 360.0); + if (textPtr->angle < 0.0) { + textPtr->angle += 360.0; + } + if (textPtr->angle == 0.0) { + textPtr->angle = 0.0; + } + textPtr->sine = sin(textPtr->angle * PI/180.0); + textPtr->cosine = cos(textPtr->angle * PI/180.0); + ComputeTextBbox(canvas, textPtr); return TCL_OK; } @@ -603,10 +628,11 @@ ComputeTextBbox( TextItem *textPtr) /* Item whose bbox is to be recomputed. */ { Tk_CanvasTextInfo *textInfoPtr; - int leftX, topY, width, height, fudge; + int leftX, topY, width, height, fudge, i; Tk_State state = textPtr->header.state; + double x[4], y[4], dx[4], dy[4], sinA, cosA, tmp; - if(state == TK_STATE_NULL) { + if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; } @@ -624,8 +650,11 @@ ComputeTextBbox( * bounding box for the text item. */ - leftX = (int) floor(textPtr->x + 0.5); - topY = (int) floor(textPtr->y + 0.5); + leftX = ROUND(textPtr->x); + topY = ROUND(textPtr->y); + for (i=0 ; i<4 ; i++) { + dx[i] = dy[i] = 0.0; + } switch (textPtr->anchor) { case TK_ANCHOR_NW: case TK_ANCHOR_N: @@ -636,12 +665,18 @@ ComputeTextBbox( case TK_ANCHOR_CENTER: case TK_ANCHOR_E: topY -= height / 2; + for (i=0 ; i<4 ; i++) { + dy[i] = -height / 2; + } break; case TK_ANCHOR_SW: case TK_ANCHOR_S: case TK_ANCHOR_SE: topY -= height; + for (i=0 ; i<4 ; i++) { + dy[i] = -height; + } break; } switch (textPtr->anchor) { @@ -654,17 +689,27 @@ ComputeTextBbox( case TK_ANCHOR_CENTER: case TK_ANCHOR_S: leftX -= width / 2; + for (i=0 ; i<4 ; i++) { + dx[i] = -width / 2; + } break; case TK_ANCHOR_NE: case TK_ANCHOR_E: case TK_ANCHOR_SE: leftX -= width; + for (i=0 ; i<4 ; i++) { + dx[i] = -width; + } break; } - textPtr->leftEdge = leftX; - textPtr->rightEdge = leftX + width; + textPtr->actualWidth = width; + + sinA = textPtr->sine; + cosA = textPtr->cosine; + textPtr->drawOrigin[0] = textPtr->x + dx[0]*cosA + dy[0]*sinA; + textPtr->drawOrigin[1] = textPtr->y + dy[0]*cosA - dx[0]*sinA; /* * Last of all, update the bounding box for the item. The item's bounding @@ -677,10 +722,50 @@ ComputeTextBbox( if (textInfoPtr->selBorderWidth > fudge) { fudge = textInfoPtr->selBorderWidth; } - textPtr->header.x1 = leftX - fudge; - textPtr->header.y1 = topY; - textPtr->header.x2 = leftX + width + fudge; - textPtr->header.y2 = topY + height; + + /* + * Apply the rotation before computing the bounding box. + */ + + dx[0] -= fudge; + dx[1] += width + fudge; + dx[2] += width + fudge; + dy[2] += height; + dx[3] -= fudge; + dy[3] += height; + for (i=0 ; i<4 ; i++) { + x[i] = textPtr->x + dx[i] * cosA + dy[i] * sinA; + y[i] = textPtr->y + dy[i] * cosA - dx[i] * sinA; + } + + /* + * Convert to a rectilinear bounding box. + */ + + for (i=1,tmp=x[0] ; i<4 ; i++) { + if (x[i] < tmp) { + tmp = x[i]; + } + } + textPtr->header.x1 = ROUND(tmp); + for (i=1,tmp=y[0] ; i<4 ; i++) { + if (y[i] < tmp) { + tmp = y[i]; + } + } + textPtr->header.y1 = ROUND(tmp); + for (i=1,tmp=x[0] ; i<4 ; i++) { + if (x[i] > tmp) { + tmp = x[i]; + } + } + textPtr->header.x2 = ROUND(tmp); + for (i=1,tmp=y[0] ; i<4 ; i++) { + if (y[i] > tmp) { + tmp = y[i]; + } + } + textPtr->header.y2 = ROUND(tmp); } /* @@ -720,16 +805,16 @@ DisplayCanvText( textPtr = (TextItem *) itemPtr; textInfoPtr = textPtr->textInfoPtr; - if(state == TK_STATE_NULL) { + if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; } stipple = textPtr->stipple; if (Canvas(canvas)->currentItemPtr == itemPtr) { - if (textPtr->activeStipple!=None) { + if (textPtr->activeStipple != None) { stipple = textPtr->activeStipple; } - } else if (state==TK_STATE_DISABLED) { - if (textPtr->disabledStipple!=None) { + } else if (state == TK_STATE_DISABLED) { + if (textPtr->disabledStipple != None) { stipple = textPtr->disabledStipple; } } @@ -750,6 +835,8 @@ DisplayCanvText( selFirstChar = -1; selLastChar = 0; /* lint. */ + Tk_CanvasDrawableCoords(canvas, textPtr->drawOrigin[0], + textPtr->drawOrigin[1], &drawableX, &drawableY); if (textInfoPtr->selItemPtr == itemPtr) { selFirstChar = textInfoPtr->selectFirst; @@ -780,20 +867,30 @@ DisplayCanvText( x = xFirst; height = hFirst; for (y = yFirst ; y <= yLast; y += height) { + int dx1, dy1, dx2, dy2; + double s = textPtr->sine, c = textPtr->cosine; + XPoint points[4]; + if (y == yLast) { width = xLast + wLast - x; } else { - width = textPtr->rightEdge - textPtr->leftEdge - x; + width = textPtr->actualWidth - x; } - Tk_CanvasDrawableCoords(canvas, - (double) (textPtr->leftEdge + x - - textInfoPtr->selBorderWidth), - (double) (textPtr->header.y1 + y), - &drawableX, &drawableY); - Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable, - textInfoPtr->selBorder, drawableX, drawableY, - width + 2 * textInfoPtr->selBorderWidth, - height, textInfoPtr->selBorderWidth, TK_RELIEF_RAISED); + dx1 = x - textInfoPtr->selBorderWidth; + dy1 = y; + dx2 = width + 2 * textInfoPtr->selBorderWidth; + dy2 = height; + points[0].x = drawableX + dx1*c + dy1*s; + points[0].y = drawableY + dy1*c - dx1*s; + points[1].x = drawableX + (dx1+dx2)*c + dy1*s; + points[1].y = drawableY + dy1*c - (dx1+dx2)*s; + points[2].x = drawableX + (dx1+dx2)*c + (dy1+dy2)*s; + points[2].y = drawableY + (dy1+dy2)*c - (dx1+dx2)*s; + points[3].x = drawableX + dx1*c + (dy1+dy2)*s; + points[3].y = drawableY + (dy1+dy2)*c - dx1*s; + Tk_Fill3DPolygon(Tk_CanvasTkwin(canvas), drawable, + textInfoPtr->selBorder, points, 4, + textInfoPtr->selBorderWidth, TK_RELIEF_RAISED); x = 0; } } @@ -811,18 +908,28 @@ DisplayCanvText( if ((textInfoPtr->focusItemPtr == itemPtr) && (textInfoPtr->gotFocus)) { if (Tk_CharBbox(textPtr->textLayout, textPtr->insertPos, &x, &y, NULL, &height)) { - Tk_CanvasDrawableCoords(canvas, - (double) (textPtr->leftEdge + x - - (textInfoPtr->insertWidth / 2)), - (double) (textPtr->header.y1 + y), - &drawableX, &drawableY); - Tk_SetCaretPos(Tk_CanvasTkwin(canvas), drawableX, drawableY, + int dx1, dy1, dx2, dy2; + double s = textPtr->sine, c = textPtr->cosine; + XPoint points[4]; + + dx1 = x - (textInfoPtr->insertWidth / 2); + dy1 = y; + dx2 = textInfoPtr->insertWidth; + dy2 = height; + points[0].x = drawableX + dx1*c + dy1*s; + points[0].y = drawableY + dy1*c - dx1*s; + points[1].x = drawableX + (dx1+dx2)*c + dy1*s; + points[1].y = drawableY + dy1*c - (dx1+dx2)*s; + points[2].x = drawableX + (dx1+dx2)*c + (dy1+dy2)*s; + points[2].y = drawableY + (dy1+dy2)*c - (dx1+dx2)*s; + points[3].x = drawableX + dx1*c + (dy1+dy2)*s; + points[3].y = drawableY + (dy1+dy2)*c - dx1*s; + + Tk_SetCaretPos(Tk_CanvasTkwin(canvas), points[0].x, points[0].y, height); if (textInfoPtr->cursorOn) { - Tk_Fill3DRectangle(Tk_CanvasTkwin(canvas), drawable, - textInfoPtr->insertBorder, - drawableX, drawableY, - textInfoPtr->insertWidth, height, + Tk_Fill3DPolygon(Tk_CanvasTkwin(canvas), drawable, + textInfoPtr->insertBorder, points, 4, textInfoPtr->insertBorderWidth, TK_RELIEF_RAISED); } else if (textPtr->cursorOffGC != None) { /* @@ -832,10 +939,8 @@ DisplayCanvText( * where both may be drawn in the same color. */ - XFillRectangle(display, drawable, textPtr->cursorOffGC, - drawableX, drawableY, - (unsigned) textInfoPtr->insertWidth, - (unsigned) height); + XFillPolygon(display, drawable, textPtr->cursorOffGC, + points, 4, Convex, CoordModeOrigin); } } } @@ -850,23 +955,24 @@ DisplayCanvText( * anti-aliasing colors would blend together. */ - Tk_CanvasDrawableCoords(canvas, (double) textPtr->leftEdge, - (double) textPtr->header.y1, &drawableX, &drawableY); - if ((selFirstChar >= 0) && (textPtr->selTextGC != textPtr->gc)) { - Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, - drawableX, drawableY, 0, selFirstChar); - Tk_DrawTextLayout(display, drawable, textPtr->selTextGC, - textPtr->textLayout, drawableX, drawableY, selFirstChar, - selLastChar + 1); - Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, - drawableX, drawableY, selLastChar + 1, -1); + TkDrawAngledTextLayout(display, drawable, textPtr->gc, + textPtr->textLayout, drawableX, drawableY, textPtr->angle, + 0, selFirstChar); + TkDrawAngledTextLayout(display, drawable, textPtr->selTextGC, + textPtr->textLayout, drawableX, drawableY, textPtr->angle, + selFirstChar, selLastChar + 1); + TkDrawAngledTextLayout(display, drawable, textPtr->gc, + textPtr->textLayout, drawableX, drawableY, textPtr->angle, + selLastChar + 1, -1); } else { - Tk_DrawTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, - drawableX, drawableY, 0, -1); + TkDrawAngledTextLayout(display, drawable, textPtr->gc, + textPtr->textLayout, drawableX, drawableY, textPtr->angle, + 0, -1); } - Tk_UnderlineTextLayout(display, drawable, textPtr->gc, textPtr->textLayout, - drawableX, drawableY, textPtr->underline); + TkUnderlineAngledTextLayout(display, drawable, textPtr->gc, + textPtr->textLayout, drawableX, drawableY, textPtr->angle, + textPtr->underline); if (stipple != None) { XSetTSOrigin(display, textPtr->gc, 0, 0); @@ -1076,15 +1182,17 @@ TextToPoint( { TextItem *textPtr; Tk_State state = itemPtr->state; - double value; + double value, px, py; if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; } textPtr = (TextItem *) itemPtr; + px = pointPtr[0] - textPtr->drawOrigin[0]; + py = pointPtr[1] - textPtr->drawOrigin[1]; value = (double) Tk_DistanceToTextLayout(textPtr->textLayout, - (int) pointPtr[0] - textPtr->leftEdge, - (int) pointPtr[1] - textPtr->header.y1); + (int) px*textPtr->cosine - py*textPtr->sine, + (int) py*textPtr->cosine + px*textPtr->sine); if ((state == TK_STATE_HIDDEN) || (textPtr->color == NULL) || (textPtr->text == NULL) || (*textPtr->text == 0)) { @@ -1128,11 +1236,12 @@ TextToArea( } textPtr = (TextItem *) itemPtr; - return Tk_IntersectTextLayout(textPtr->textLayout, - (int) (rectPtr[0] + 0.5) - textPtr->leftEdge, - (int) (rectPtr[1] + 0.5) - textPtr->header.y1, + return TkIntersectAngledTextLayout(textPtr->textLayout, + (int) (rectPtr[0] + 0.5) - textPtr->drawOrigin[0], + (int) (rectPtr[1] + 0.5) - textPtr->drawOrigin[1], (int) (rectPtr[2] - rectPtr[0] + 0.5), - (int) (rectPtr[3] - rectPtr[1] + 0.5)); + (int) (rectPtr[3] - rectPtr[1] + 0.5), + textPtr->angle); } /* @@ -1261,7 +1370,7 @@ GetTextIndex( *indexPtr = textInfoPtr->selectLast; } else if (c == '@') { int x, y; - double tmp; + double tmp, c = textPtr->cosine, s = textPtr->sine; char *end, *p; p = string+1; @@ -1276,9 +1385,9 @@ GetTextIndex( goto badIndex; } y = (int) ((tmp < 0) ? tmp - 0.5 : tmp + 0.5); - *indexPtr = Tk_PointToChar(textPtr->textLayout, - x + canvasPtr->scrollX1 - textPtr->leftEdge, - y + canvasPtr->scrollY1 - textPtr->header.y1); + x += canvasPtr->scrollX1 - textPtr->drawOrigin[0]; + y += canvasPtr->scrollY1 - textPtr->drawOrigin[1]; + *indexPtr = Tk_PointToChar(textPtr->textLayout, x*c-y*s, y*c+x*s); } else if (Tcl_GetIntFromObj(NULL, obj, indexPtr) == TCL_OK) { if (*indexPtr < 0) { *indexPtr = 0; @@ -1420,10 +1529,9 @@ TextToPostscript( * being created. */ { TextItem *textPtr = (TextItem *) itemPtr; - int x, y; + double x, y; Tk_FontMetrics fm; const char *justify; - char buffer[500]; XColor *color; Pixmap stipple; Tk_State state = itemPtr->state; @@ -1437,17 +1545,17 @@ TextToPostscript( textPtr->text == NULL || *textPtr->text == 0) { return TCL_OK; } else if (Canvas(canvas)->currentItemPtr == itemPtr) { - if (textPtr->activeColor!=NULL) { + if (textPtr->activeColor != NULL) { color = textPtr->activeColor; } - if (textPtr->activeStipple!=None) { + if (textPtr->activeStipple != None) { stipple = textPtr->activeStipple; } - } else if (state==TK_STATE_DISABLED) { - if (textPtr->disabledColor!=NULL) { + } else if (state == TK_STATE_DISABLED) { + if (textPtr->disabledColor != NULL) { color = textPtr->disabledColor; } - if (textPtr->disabledStipple!=None) { + if (textPtr->disabledStipple != None) { stipple = textPtr->disabledStipple; } } @@ -1467,9 +1575,8 @@ TextToPostscript( Tcl_AppendResult(interp, "} bind def\n", NULL); } - sprintf(buffer, "%.15g %.15g [\n", textPtr->x, - Tk_CanvasPsY(canvas, textPtr->y)); - Tcl_AppendResult(interp, buffer, NULL); + Tcl_AppendPrintfToObj(Tcl_GetObjResult(interp), "%.15g %.15g %.15g [\n", + textPtr->angle, textPtr->x, Tk_CanvasPsY(canvas, textPtr->y)); Tk_TextLayoutToPostscript(interp, textPtr->textLayout); @@ -1492,15 +1599,10 @@ TextToPostscript( } Tk_GetFontMetrics(textPtr->tkfont, &fm); - sprintf(buffer, "] %d ", fm.linespace); - Tcl_AppendResult(interp, buffer, NULL); - Tcl_PrintDouble(NULL, x / -2.0, buffer); - Tcl_AppendResult(interp, buffer, " ", NULL); - Tcl_PrintDouble(NULL, y / 2.0, buffer); - Tcl_AppendResult(interp, buffer, NULL); - sprintf(buffer, " %s %s DrawText\n", justify, + Tcl_AppendPrintfToObj(Tcl_GetObjResult(interp), + "] %d %g %g %s %s DrawText\n", + fm.linespace, x / -2.0, y / 2.0, justify, ((stipple == None) ? "false" : "true")); - Tcl_AppendResult(interp, buffer, NULL); return TCL_OK; } diff --git a/generic/tkFont.c b/generic/tkFont.c index a0fac74..c3b0e72 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkFont.c,v 1.48 2008/11/02 09:54:02 nijtmans Exp $ + * RCS: @(#) $Id: tkFont.c,v 1.49 2008/11/22 18:08:51 dkf Exp $ */ #include "tkInt.h" @@ -888,7 +888,7 @@ RecomputeWidgets( Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc); if (proc != NULL) { - (*proc)(winPtr->instanceData); + proc(winPtr->instanceData); } /* @@ -1347,7 +1347,7 @@ SetFontFromAny( Tcl_GetString(objPtr); typePtr = objPtr->typePtr; if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { - (*typePtr->freeIntRepProc)(objPtr); + typePtr->freeIntRepProc(objPtr); } objPtr->typePtr = &tkFontObjType; objPtr->internalRep.twoPtrValue.ptr1 = NULL; @@ -2310,6 +2310,69 @@ Tk_DrawTextLayout( } } +void +TkDrawAngledTextLayout( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context to use for drawing text. */ + Tk_TextLayout layout, /* Layout information, from a previous call to + * Tk_ComputeTextLayout(). */ + int x, int y, /* Upper-left hand corner of rectangle in + * which to draw (pixels). */ + double angle, + int firstChar, /* The index of the first character to draw + * from the given text item. 0 specfies the + * beginning. */ + int lastChar) /* The index just after the last character to + * draw from the given text item. A number < 0 + * means to draw all characters. */ +{ + TextLayout *layoutPtr = (TextLayout *) layout; + int i, numDisplayChars, drawX; + const char *firstByte, *lastByte; + LayoutChunk *chunkPtr; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); + + if (layoutPtr == NULL) { + return; + } + + if (lastChar < 0) { + lastChar = 100000000; + } + chunkPtr = layoutPtr->chunks; + for (i = 0; i < layoutPtr->numChunks; i++) { + numDisplayChars = chunkPtr->numDisplayChars; + if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) { + double dx, dy; + + if (firstChar <= 0) { + drawX = 0; + firstChar = 0; + firstByte = chunkPtr->start; + } else { + firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar); + Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, + firstByte - chunkPtr->start, -1, 0, &drawX); + } + if (lastChar < numDisplayChars) { + numDisplayChars = lastChar; + } + lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); + dx = cosA * (chunkPtr->x + drawX) + sinA * (chunkPtr->y); + dy = -sinA * (chunkPtr->x + drawX) + cosA * (chunkPtr->y); + TkpDrawAngledChars(display, drawable, gc, layoutPtr->tkfont, + firstByte, lastByte - firstByte, x+dx, y+dy, angle); + } + firstChar -= chunkPtr->numChars; + lastChar -= chunkPtr->numChars; + if (lastChar <= 0) { + break; + } + chunkPtr++; + } +} + /* *--------------------------------------------------------------------------- * @@ -2358,6 +2421,68 @@ Tk_UnderlineTextLayout( } } +void +TkUnderlineAngledTextLayout( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context to use for drawing text. */ + Tk_TextLayout layout, /* Layout information, from a previous call to + * Tk_ComputeTextLayout(). */ + int x, int y, /* Upper-left hand corner of rectangle in + * which to draw (pixels). */ + double angle, + int underline) /* Index of the single character to underline, + * or -1 for no underline. */ +{ + int xx, yy, width, height; + + if (angle == 0.0) { + Tk_UnderlineTextLayout(display, drawable, gc, layout, x,y, underline); + return; + } + + if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0) + && (width != 0)) { + TextLayout *layoutPtr = (TextLayout *) layout; + TkFont *fontPtr = (TkFont *) layoutPtr->tkfont; + double sinA = sin(angle*PI/180), cosA = cos(angle*PI/180); + double dy = yy + fontPtr->fm.ascent + fontPtr->underlinePos; + XPoint points[5]; + + /* + * Note that we're careful to only round a double value once, which + * minimizes roundoff errors. + */ + + points[0].x = x + round(xx*cosA + dy*sinA); + points[0].y = y + round(dy*cosA - xx*sinA); + points[1].x = x + round(xx*cosA + dy*sinA + width*cosA); + points[1].y = y + round(dy*cosA - xx*sinA - width*sinA); + if (fontPtr->underlineHeight == 1) { + /* + * Thin underlines look better when rotated when drawn as a line + * rather than a rectangle; the rasterizer copes better. + */ + + XDrawLines(display, drawable, gc, points, 2, CoordModeOrigin); + } else { + points[2].x = x + round(xx*cosA + dy*sinA + width*cosA + - fontPtr->underlineHeight*sinA); + points[2].y = y + round(dy*cosA - xx*sinA - width*sinA + + fontPtr->underlineHeight*cosA); + points[3].x = x + round(xx*cosA + dy*sinA + - fontPtr->underlineHeight*sinA); + points[3].y = y + round(dy*cosA - xx*sinA + + fontPtr->underlineHeight*cosA); + points[4].x = points[0].x; + points[4].y = points[0].y; + XFillPolygon(display, drawable, gc, points, 5, Complex, + CoordModeOrigin); + XDrawLines(display, drawable, gc, points, 5, CoordModeOrigin); + } + } +} + /* *--------------------------------------------------------------------------- * @@ -2806,6 +2931,263 @@ Tk_IntersectTextLayout( /* *--------------------------------------------------------------------------- * + * TkIntersectAngledTextLayout -- + * + * Determines whether a text layout that has been turned by an angle + * about its top-left coordinae lies entirely inside, entirely outside, + * or overlaps a given rectangle. Non-displaying space characters that + * occur at the end of individual lines in the text layout are ignored + * for intersection calculations. + * + * Results: + * The return value is -1 if the text layout is entirely outside of the + * rectangle, 0 if it overlaps, and 1 if it is entirely inside of the + * rectangle. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static inline int +PointInQuadrilateral( + double qx[], + double qy[], + double x, + double y) +{ + int i; + + for (i=0 ; i<4 ; i++) { + double sideDX = qx[(i+1)%4] - qx[i]; + double sideDY = qy[(i+1)%4] - qy[i]; + double dx = x - qx[i]; + double dy = y - qy[i]; + + if (sideDX*dy < sideDY*dx) { + return 0; + } + } + return 1; +} + +static inline int +sign( + double value) +{ + if (value < 0.0) return -1; + if (value > 0.0) return 1; + return 0; +} + +static inline int +SidesIntersect( + double ax1, double ay1, double ax2, double ay2, + double bx1, double by1, double bx2, double by2) +{ +#if 0 +/* http://www.freelunchdesign.com/cgi-bin/codwiki.pl?DiscussionTopics/CollideMeUpBaby */ + + double a1, b1, c1, a2, b2, c2, r1, r2, r3, r4, denom; + + a1 = ay2 - ay1; + b1 = ax1 - ax2; + c1 = (ax2 * ay1) - (ax1 * ay2); + r3 = (a1 * bx1) + (b1 * by1) + c1; + r4 = (a1 * bx2) + (b1 * by2) + c1; + if ((r3 != 0.0) && (r4 != 0.0) && (r3*r4 > 0.0)) { + return 0; + } + + a2 = by2 - by1; + b2 = bx1 - bx2; + c2 = (bx2 * by1) - (bx1 * by2); + r1 = (a2 * ax1) + (b2 * ay1) + c2; + r2 = (a2 * ax2) + (b2 * ay2) + c2; + if ((r1 != 0.0) && (r2 != 0.0) && (r1*r2 > 0.0)) { + return 0; + } + + denom = (a1 * b2) - (a2 * b1); + return (denom != 0.0); +#else + /* + * A more efficient version. Two line segments intersect if, when seen + * from the perspective of one line, the two endpoints of the other + * segment lie on opposite sides of the line, and vice versa. "Lie on + * opposite sides" is computed by taking the cross products and seeing if + * they are of opposite signs. + */ + + double dx, dy, dx1, dy1; + + dx = ax2 - ax1; + dy = ay2 - ay1; + dx1 = bx1 - ax1; + dy1 = by1 - ay1; + if ((dx*dy1-dy*dx1 > 0.0) == (dx*(by2-ay1)-dy*(bx2-ax1) > 0.0)) { + return 0; + } + dx = bx2 - bx1; + dy = by2 - by1; + if ((dy*dx1-dx*dy1 > 0.0) == (dx*(ay2-by1)-dy*(ax2-bx1) > 0.0)) { + return 0; + } + return 1; +#endif +} + +int +TkIntersectAngledTextLayout( + Tk_TextLayout layout, /* Layout information, from a previous call to + * Tk_ComputeTextLayout(). */ + int x, int y, /* Upper-left hand corner, in pixels, of + * rectangular area to compare with text + * layout. Coordinates are with respect to the + * upper-left hand corner of the text layout + * itself. */ + int width, int height, /* The width and height of the above + * rectangular area, in pixels. */ + double angle) +{ + int i, x1, y1, x2, y2; + TextLayout *layoutPtr; + LayoutChunk *chunkPtr; + TkFont *fontPtr; + double c = cos(angle * PI/180.0), s = sin(angle * PI/180.0); + double rx[4], ry[4]; + + if (angle == 0.0) { + return Tk_IntersectTextLayout(layout, x, y, width, height); + } + + /* + * Compute the coordinates of the rectangle, rotated into text layout + * space. + */ + + rx[0] = x*c - y*s; + ry[0] = y*c + x*s; + rx[1] = (x+width)*c - y*s; + ry[1] = y*c + (x+width)*s; + rx[2] = (x+width)*c - (y+height)*s; + ry[2] = (y+height)*c + (x+width)*s; + rx[3] = x*c - (y+height)*s; + ry[3] = (y+height)*c + x*s; + + /* + * Want to know if all chunks are inside the rectangle, or if there is any + * overlap. First, we check to see if all chunks are inside; if and only + * if they are, we're in the "inside" case. + */ + + layoutPtr = (TextLayout *) layout; + chunkPtr = layoutPtr->chunks; + fontPtr = (TkFont *) layoutPtr->tkfont; + + for (i=0 ; inumChunks ; i++,chunkPtr++) { + if (chunkPtr->start[0] == '\n') { + /* + * Newline characters are not counted when computing area + * intersection (but tab characters would still be considered). + */ + + continue; + } + + x1 = chunkPtr->x; + y1 = chunkPtr->y - fontPtr->fm.ascent; + x2 = chunkPtr->x + chunkPtr->displayWidth; + y2 = chunkPtr->y + fontPtr->fm.descent; + if ( !PointInQuadrilateral(rx, ry, x1, y1) || + !PointInQuadrilateral(rx, ry, x2, y1) || + !PointInQuadrilateral(rx, ry, x2, y2) || + !PointInQuadrilateral(rx, ry, x1, y2)) { + goto notInside; + } + } + return 1; + + /* + * Next, check to see if all the points of the rectangle are inside a + * single chunk; if they are, we're in an "overlap" case. + */ + + notInside: + chunkPtr = layoutPtr->chunks; + + for (i=0 ; inumChunks ; i++,chunkPtr++) { + double cx[4], cy[4]; + if (chunkPtr->start[0] == '\n') { + /* + * Newline characters are not counted when computing area + * intersection (but tab characters would still be considered). + */ + + continue; + } + + cx[0] = cx[3] = chunkPtr->x; + cy[0] = cy[1] = chunkPtr->y - fontPtr->fm.ascent; + cx[1] = cx[2] = chunkPtr->x + chunkPtr->displayWidth; + cy[2] = cy[3] = chunkPtr->y + fontPtr->fm.descent; + if ( !PointInQuadrilateral(cx, cy, rx[0], ry[0]) || + !PointInQuadrilateral(cx, cy, rx[1], ry[1]) || + !PointInQuadrilateral(cx, cy, rx[2], ry[2]) || + !PointInQuadrilateral(cx, cy, rx[3], ry[3])) { + goto notReverseInside; + } + } + return 0; + + /* + * If we're overlapping now, we must be partially in and out of at least + * one chunk. If that is the case, there must be one line segment of the + * rectangle that is touching or crossing a line segment of a chunk. + */ + + notReverseInside: + chunkPtr = layoutPtr->chunks; + + for (i=0 ; inumChunks ; i++,chunkPtr++) { + int j; + + if (chunkPtr->start[0] == '\n') { + /* + * Newline characters are not counted when computing area + * intersection (but tab characters would still be considered). + */ + + continue; + } + + x1 = chunkPtr->x; + y1 = chunkPtr->y - fontPtr->fm.ascent; + x2 = chunkPtr->x + chunkPtr->displayWidth; + y2 = chunkPtr->y + fontPtr->fm.descent; + + for (j=0 ; j<4 ; j++) { + int k = (j+1) % 4; + if ( SidesIntersect(rx[j],ry[j], rx[k],ry[k], x1,y1, x2,y1) || + SidesIntersect(rx[j],ry[j], rx[k],ry[k], x2,y1, x2,y2) || + SidesIntersect(rx[j],ry[j], rx[k],ry[k], x2,y2, x1,y2) || + SidesIntersect(rx[j],ry[j], rx[k],ry[k], x1,y2, x1,y1)) { + return 0; + } + } + } + + /* + * They must be wholly non-overlapping. + */ + + return -1; +} + +/* + *--------------------------------------------------------------------------- + * * Tk_TextLayoutToPostscript -- * * Outputs the contents of a text layout in Postscript format. The set of diff --git a/generic/tkInt.h b/generic/tkInt.h index 10fff59..5fe85e1 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: $Id: tkInt.h,v 1.92 2008/11/09 21:53:39 nijtmans Exp $ + * RCS: $Id: tkInt.h,v 1.93 2008/11/22 18:08:51 dkf Exp $ */ #ifndef _TKINT @@ -956,6 +956,19 @@ MODULE_SCOPE TkMainInfo *tkMainWindowList; MODULE_SCOPE Tk_ImageType tkPhotoImageType; MODULE_SCOPE Tcl_HashTable tkPredefBitmapTable; +/* + * The definition of pi, at least from the perspective of double-precision + * floats. + */ + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +/* + * Exported internals. + */ + #include "tkIntDecls.h" #ifdef BUILD_tk @@ -1214,6 +1227,19 @@ MODULE_SCOPE void TkpCreateBusy(Tk_FakeWin *winPtr, Tk_Window tkRef, Window *parentPtr, Tk_Window tkParent, TkBusy busy); +MODULE_SCOPE void TkDrawAngledTextLayout(Display *display, + Drawable drawable, GC gc, Tk_TextLayout layout, + int x, int y, double angle, int firstChar, + int lastChar); +MODULE_SCOPE void TkpDrawAngledChars(Display *display,Drawable drawable, + GC gc, Tk_Font tkfont, const char *source, + int numBytes, double x, double y, double angle); +MODULE_SCOPE void TkUnderlineAngledTextLayout(Display *display, + Drawable drawable, GC gc, Tk_TextLayout layout, + int x, int y, double angle, int underline); +MODULE_SCOPE int TkIntersectAngledTextLayout(Tk_TextLayout layout, + int x,int y, int width, int height, double angle); + /* * Unsupported commands. */ diff --git a/library/prolog.ps b/library/prolog.ps index 9c76878..a82c3d2 100644 --- a/library/prolog.ps +++ b/library/prolog.ps @@ -3,7 +3,7 @@ % This is a standard prolog for Postscript generated by Tk's canvas % widget. -% RCS: @(#) $Id: prolog.ps,v 1.3 1999/02/04 20:59:48 stanton Exp $ +% RCS: @(#) $Id: prolog.ps,v 1.4 2008/11/22 18:08:51 dkf Exp $ % The definitions below just define all of the variables used in % any of the procedures here. This is needed for obscure reasons @@ -189,11 +189,12 @@ systemdict /ISOLatin1Encoding known not { } if } bind def -% x y strings spacing xoffset yoffset justify stipple DrawText -- +% angle x y strings spacing xoffset yoffset justify stipple DrawText -- % This procedure does all of the real work of drawing text. The % color and font must already have been set by the caller, and the % following arguments must be on the stack: % +% angle - Angle through which to rotate text, in degrees. % x, y - Coordinates at which to draw text. % strings - An array of strings, one for each line of the text item, % in order from top to bottom. @@ -235,11 +236,12 @@ systemdict /ISOLatin1Encoding known not { exch pop exch sub /height exch def pop newpath - % Translate coordinates first so that the origin is at the upper-left - % corner of the text's bounding box. Remember that x and y for - % positioning are still on the stack. + % Translate and rotatecoordinates first so that the origin is at the + % upper-left corner of the text's bounding box. Remember that angle, x and + % y for positioning are still on the stack. translate + rotate lineLength xoffset mul strings length 1 sub spacing mul height add yoffset mul translate diff --git a/macosx/tkMacOSXFont.c b/macosx/tkMacOSXFont.c index 921cf93..ca11b69 100644 --- a/macosx/tkMacOSXFont.c +++ b/macosx/tkMacOSXFont.c @@ -35,7 +35,7 @@ * that such fonts can not be used for controls, because controls * definitely require a family id (this assertion needs testing). * - * RCS: @(#) $Id: tkMacOSXFont.c,v 1.40 2008/11/02 09:54:02 nijtmans Exp $ + * RCS: @(#) $Id: tkMacOSXFont.c,v 1.41 2008/11/22 18:08:51 dkf Exp $ */ #include "tkMacOSXPrivate.h" @@ -262,7 +262,10 @@ static OSStatus GetThemeFontAndFamily(const ThemeFontID themeFontId, static void InitSystemFonts(TkMainInfo *mainPtr); static int CreateNamedSystemFont(Tcl_Interp *interp, Tk_Window tkwin, const char* name, TkFontAttributes *faPtr); - +static void DrawCharsInContext(Display *display, + Drawable drawable, GC gc, Tk_Font tkfont, + const char *source, int numBytes, int rangeStart, + int rangeLength, int x, int y, double angle); /* *------------------------------------------------------------------------- @@ -1135,8 +1138,31 @@ Tk_DrawChars( int x, int y) /* Coordinates at which to place origin of the * string when drawing. */ { - TkpDrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, - 0, numBytes, x, y); + DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, + 0, numBytes, x, y, 0.0); +} + +void +TkpDrawAngledChars( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + double x, double y, /* Coordinates at which to place origin of + * string when drawing. */ + double angle) /* What angle to put text at, in degrees. */ +{ + DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, + 0, numBytes, x, y, angle); } /* @@ -1180,6 +1206,32 @@ TkpDrawCharsInContext( * whole (not just the range) string when * drawing. */ { + DrawCharsInContext(display, drawable, gc, tkfont, source, numBytes, + rangeStart, rangeLength, x, y, 0.0); +} + +static void +DrawCharsInContext( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; must + * be the same as font used in GC. */ + const char * source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + int rangeStart, /* Index of first byte to draw. */ + int rangeLength, /* Length of range to draw in bytes. */ + int x, int y, /* Coordinates at which to place origin of the + * whole (not just the range) string when + * drawing. */ + double angle) +{ const MacFont * fontPtr = (const MacFont *) tkfont; MacDrawable *macWin = (MacDrawable *) drawable; Fixed fx, fy; @@ -1242,6 +1294,16 @@ TkpDrawCharsInContext( urstart = Tcl_NumUtfChars(source, rangeStart); urlen = Tcl_NumUtfChars(source+rangeStart,rangeLength); + /* + * Rotate the coordinate system for Quarz drawing. + */ + + if (drawingContext.context && angle != 0.0) { + CGContextTranslateCTM(drawingContext.context, x, y); + CGContextRotateCTM(drawingContext.context, angle * PI/180.0); + CGContextTranslateCTM(drawingContext.context, -x, -y); + } + ChkErr(ATSUDrawText, fontPtr->atsuLayout, lineOffset+urstart, urlen, fx, fy); diff --git a/tests/canvText.test b/tests/canvText.test index 96a362a..2ca02f0 100644 --- a/tests/canvText.test +++ b/tests/canvText.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: canvText.test,v 1.21 2008/10/11 06:47:25 dkf Exp $ +# RCS: @(#) $Id: canvText.test,v 1.22 2008/11/22 18:08:51 dkf Exp $ package require tcltest 2.2 namespace import ::tcltest::* @@ -27,7 +27,6 @@ test canvText-1.1 {configuration options: good value for "anchor"} -body { test canvasText-1.2 {configuration options: bad value for "anchor"} -body { .c itemconfigure test -anchor xyz } -returnCodes error -result {bad anchor position "xyz": must be n, ne, e, se, s, sw, w, nw, or center} - test canvText-1.3 {configuration options: good value for "fill"} -body { .c itemconfigure test -fill #ff0000 list [lindex [.c itemconfigure test -fill] 4] [.c itemcget test -fill] @@ -39,7 +38,6 @@ test canvText-1.5 {configuration options: good value for "fill"} -body { .c itemconfigure test -fill {} list [lindex [.c itemconfigure test -fill] 4] [.c itemcget test -fill] } -result {{} {}} - test canvText-1.6 {configuration options: good value for "font"} -body { .c itemconfigure test -font {Times 40} list [lindex [.c itemconfigure test -font] 4] [.c itemcget test -font] @@ -47,7 +45,6 @@ test canvText-1.6 {configuration options: good value for "font"} -body { test canvasText-1.7 {configuration options: bad value for "font"} -body { .c itemconfigure test -font {} } -returnCodes error -result {font "" doesn't exist} - test canvText-1.8 {configuration options: good value for "justify"} -body { .c itemconfigure test -justify left list [lindex [.c itemconfigure test -justify] 4] [.c itemcget test -justify] @@ -55,7 +52,6 @@ test canvText-1.8 {configuration options: good value for "justify"} -body { test canvasText-1.9 {configuration options: bad value for "justify"} -body { .c itemconfigure test -justify xyz } -returnCodes error -result {bad justification "xyz": must be left, right, or center} - test canvText-1.10 {configuration options: good value for "stipple"} -body { .c itemconfigure test -stipple gray50 list [lindex [.c itemconfigure test -stipple] 4] [.c itemcget test -stipple] @@ -63,7 +59,6 @@ test canvText-1.10 {configuration options: good value for "stipple"} -body { test canvasText-1.11 {configuration options: bad value for "stipple"} -body { .c itemconfigure test -stipple xyz } -returnCodes error -result {bitmap "xyz" not defined} - test canvText-1.12 {configuration options: good value for "underline"} -body { .c itemconfigure test -underline 0 list [lindex [.c itemconfigure test -underline] 4] [.c itemcget test -underline] @@ -71,7 +66,6 @@ test canvText-1.12 {configuration options: good value for "underline"} -body { test canvasText-1.13 {configuration options: bad value for "underline"} -body { .c itemconfigure test -underline xyz } -returnCodes error -result {expected integer but got "xyz"} - test canvText-1.14 {configuration options: good value for "width"} -body { .c itemconfigure test -width 6 list [lindex [.c itemconfigure test -width] 4] [.c itemcget test -width] @@ -79,11 +73,25 @@ test canvText-1.14 {configuration options: good value for "width"} -body { test canvasText-1.15 {configuration options: bad value for "width"} -body { .c itemconfigure test -width xyz } -returnCodes error -result {bad screen distance "xyz"} - test canvText-1.16 {configuration options: good value for "tags"} -body { .c itemconfigure test -tags {test a b c} list [lindex [.c itemconfigure test -tags] 4] [.c itemcget test -tags] } -result {{test a b c} {test a b c}} +test canvasText-1.17 {configuration options: bad value for "angle"} -body { + .c itemconfigure test -angle xyz +} -returnCodes error -result {expected floating-point number but got "xyz"} +test canvasText-1.18 {configuration options: good value for "angle"} -body { + .c itemconfigure test -angle 32.5 + list [lindex [.c itemconfigure test -angle] 4] [.c itemcget test -angle] +} -result {32.5 32.5} +test canvasText-1.19 {configuration options: bounding of "angle"} -body { + .c itemconfigure test -angle 390 + set result [.c itemcget test -angle] + .c itemconfigure test -angle -30 + lappend result [.c itemcget test -angle] + .c itemconfigure test -angle -360 + lappend result [.c itemcget test -angle] +} -result {30.0 330.0 0.0} .c delete test @@ -93,17 +101,17 @@ test canvText-2.1 {CreateText procedure: args} -body { test canvText-2.2 {CreateText procedure: args} -body { .c create text xyz 0 } -cleanup { - .c delete all + .c delete all } -returnCodes {error} -result {bad screen distance "xyz"} test canvText-2.3 {CreateText procedure: args} -body { .c create text 0 xyz } -cleanup { - .c delete all + .c delete all } -returnCodes {error} -result {bad screen distance "xyz"} test canvText-2.4 {CreateText procedure: args} -body { .c create text 0 0 -xyz xyz } -cleanup { - .c delete all + .c delete all } -returnCodes {error} -result {unknown option "-xyz"} test canvText-2.5 {CreateText procedure} -body { .c create text 0 0 -tags x @@ -114,29 +122,29 @@ test canvText-2.5 {CreateText procedure} -body { test canvText-3.1 {TextCoords procedure} -body { - .c create text 20 20 -tag test - .c coords test 0 0 - update + .c create text 20 20 -tag test + .c coords test 0 0 + update .c coords test } -cleanup { - .c delete test + .c delete test } -result {0.0 0.0} test canvText-3.2 {TextCoords procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c coords test xyz 0 } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {bad screen distance "xyz"} test canvText-3.3 {TextCoords procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c coords test 0 xyz } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {bad screen distance "xyz"} test canvText-3.4 {TextCoords procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c coords test 10 10 set result {} @@ -145,75 +153,73 @@ test canvText-3.4 {TextCoords procedure} -setup { } return $result } -cleanup { - .c delete test + .c delete test } -result {10.0 10.0} test canvText-3.5 {TextCoords procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c coords test 10 } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {wrong # coordinates: expected 2, got 1} test canvText-3.6 {TextCoords procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c coords test 10 10 10 } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {wrong # coordinates: expected 0 or 2, got 3} test canvText-4.1 {ConfigureText procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c itemconfig test -fill xyz } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {unknown color name "xyz"} test canvText-4.2 {ConfigureText procedure} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c itemconfig test -fill blue .c itemcget test -fill } -cleanup { - .c delete test + .c delete test } -result {blue} test canvText-4.3 {ConfigureText procedure: construct font gcs} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c itemconfig test -font "times 20" -fill black -stipple gray50 list [.c itemcget test -font] [.c itemcget test -fill] [.c itemcget test -stipple] } -cleanup { - .c delete test + .c delete test } -result {{times 20} black gray50} test canvText-4.4 {ConfigureText procedure: construct cursor gc} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c select from test 2 .c select to test 4 .c icursor test 3 - # Both black -> cursor becomes white. .c config -insertbackground black .c config -selectbackground black .c itemconfig test -just left update - # Both same color (and not black) -> cursor becomes black. .c config -insertbackground red .c config -selectbackground red .c itemconfig test -just left update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-4.5 {ConfigureText procedure: adjust selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test set x {} } -body { .c itemconfig test -text "abcdefghi" @@ -235,10 +241,10 @@ test canvText-4.5 {ConfigureText procedure: adjust selection} -setup { .c dchars test 4 end lappend x [selection get] } -cleanup { - .c delete test + .c delete test } -result {cdefg 1 cdefg cd cdef cd} test canvText-4.6 {ConfigureText procedure: adjust cursor} -setup { - .c create text 20 20 -tag test + .c create text 20 20 -tag test } -body { .c itemconfig test -text "abcdefghi" .c icursor test 6 @@ -250,154 +256,128 @@ test canvText-4.6 {ConfigureText procedure: adjust cursor} -setup { test canvText-5.1 {ConfigureText procedure: adjust cursor} -body { - .c create text 10 10 -tag x -fill blue -font "times 40" -stipple gray50 -text "xyz" + .c create text 10 10 -tag x -fill blue -font "times 40" -stipple gray50 \ + -text "xyz" .c delete x } -result {} -test canvText-6.1 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.1 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor n; .c bbox test] \ - eq "[expr -$ax/2-1] 0 [expr $ax/2+1] $ay"} + eq "[expr -$ax/2-1] 0 [expr $ax/2+1] $ay"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.2 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.2 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor nw; .c bbox test] \ - eq "-1 0 [expr $ax+1] $ay"} + eq "-1 0 [expr $ax+1] $ay"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.3 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.3 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor w; .c bbox test] \ - eq "-1 [expr -$ay/2] [expr $ax+1] [expr $ay/2]"} + eq "-1 [expr -$ay/2] [expr $ax+1] [expr $ay/2]"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.4 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.4 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor sw; .c bbox test] \ - eq "-1 -$ay [expr $ax+1] 0"} + eq "-1 -$ay [expr $ax+1] 0"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.5 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.5 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor s; .c bbox test] \ - eq "[expr -$ax/2-1] -$ay [expr $ax/2+1] 0"} + eq "[expr -$ax/2-1] -$ay [expr $ax/2+1] 0"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.6 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.6 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor se; .c bbox test] \ - eq "[expr -$ax-1] -$ay 1 0"} + eq "[expr -$ax-1] -$ay 1 0"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.7 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.7 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor e; .c bbox test]\ - eq "[expr -$ax-1] [expr -$ay/2] 1 [expr $ay/2]"} + eq "[expr -$ax-1] [expr -$ay/2] 1 [expr $ay/2]"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.8 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.8 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor ne; .c bbox test] \ - eq "[expr -$ax-1] 0 1 $ay"} + eq "[expr -$ax-1] 0 1 $ay"} } -cleanup { - .c delete test + .c delete test } -result 1 -test canvText-6.9 {ComputeTextBbox procedure} -constraints { - fonts -} -setup { - .c delete test +test canvText-6.9 {ComputeTextBbox procedure} -constraints fonts -setup { + .c delete test } -body { - set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" - set ay [font metrics $font -linespace] - set ax [font measure $font 0] - - .c create text 0 0 -tag test + set font "-adobe-times-medium-r-normal--*-200-*-*-*-*-*-*" + set ay [font metrics $font -linespace] + set ax [font measure $font 0] + .c create text 0 0 -tag test .c itemconfig test -font $font -text 0 expr {[.c itemconfig test -anchor center; .c bbox test] \ - eq "[expr -$ax/2-1] [expr -$ay/2] [expr $ax/2+1] [expr $ay/2]"} + eq "[expr -$ax/2-1] [expr -$ay/2] [expr $ax/2+1] [expr $ay/2]"} } -cleanup { - .c delete test + .c delete test } -result 1 @@ -409,100 +389,100 @@ focus .c .c focus test .c itemconfig test -text "abcd\nefghi\njklmnopq" test canvText-7.1 {DisplayText procedure: stippling} -body { - .c create text 20 20 -tag test + .c create text 20 20 -tag test .c itemconfig test -stipple gray50 update .c itemconfig test -stipple {} update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-7.2 {DisplayText procedure: draw selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { - .c itemconfig test -text "abcd\nefghi\njklmnopq" + .c itemconfig test -text "abcd\nefghi\njklmnopq" .c select from test 0 .c select to test end update selection get } -cleanup { - .c delete test + .c delete test } -result "abcd\nefghi\njklmnopq" test canvText-7.3 {DisplayText procedure: selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { - .c itemconfig test -text "abcd\nefghi\njklmnopq" + .c itemconfig test -text "abcd\nefghi\njklmnopq" .c select from test 0 .c select to test end update selection get } -cleanup { - .c delete test + .c delete test } -result "abcd\nefghi\njklmnopq" test canvText-7.4 {DisplayText procedure: one line selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { - .c itemconfig test -text "abcd\nefghi\njklmnopq" + .c itemconfig test -text "abcd\nefghi\njklmnopq" .c select from test 2 .c select to test 3 update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-7.5 {DisplayText procedure: multi-line selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { - .c itemconfig test -text "abcd\nefghi\njklmnopq" + .c itemconfig test -text "abcd\nefghi\njklmnopq" .c select from test 2 .c select to test 12 update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-7.6 {DisplayText procedure: draw cursor} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { - .c itemconfig test -text "abcd\nefghi\njklmnopq" + .c itemconfig test -text "abcd\nefghi\njklmnopq" .c icursor test 3 update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-7.7 {DisplayText procedure: selected text different color} -setup { - .c create text 20 20 -tag test - .c itemconfig test -text "abcd\nefghi\njklmnopq" - focus .c - .c focus test + .c create text 20 20 -tag test + .c itemconfig test -text "abcd\nefghi\njklmnopq" + focus .c + .c focus test } -body { .c config -selectforeground blue .c itemconfig test -anchor n update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-7.8 {DisplayText procedure: not selected} -setup { - .c create text 20 20 -tag test - .c itemconfig test -text "abcd\nefghi\njklmnopq" - focus .c - .c focus test + .c create text 20 20 -tag test + .c itemconfig test -text "abcd\nefghi\njklmnopq" + focus .c + .c focus test } -body { .c select clear update } -cleanup { - .c delete test + .c delete test } -result {} test canvText-7.9 {DisplayText procedure: select end} -setup { - destroy .t + destroy .t } -body { toplevel .t wm geometry .t +0+0 @@ -516,26 +496,26 @@ test canvText-7.9 {DisplayText procedure: select end} -setup { #catch {destroy .t} update } -cleanup { - destroy .t + destroy .t } -result {} test canvText-8.1 {TextInsert procedure: 0 length insert} -setup { - .c create text 20 20 -tag test - .c itemconfig test -text "abcd\nefghi\njklmnopq" - focus .c - .c focus test + .c create text 20 20 -tag test + .c itemconfig test -text "abcd\nefghi\njklmnopq" + focus .c + .c focus test } -body { .c insert test end {} } -cleanup { - .c delete test + .c delete test } -result {} test canvText-8.2 {TextInsert procedure: before beginning/after end} -body { # Can't test this because GetTextIndex filters out those numbers. } -result {} test canvText-8.3 {TextInsert procedure: inserting in a selected item} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c select from test 2 @@ -544,9 +524,9 @@ test canvText-8.3 {TextInsert procedure: inserting in a selected item} -setup { .c itemcget test -text } -result {axyzbcdefg} test canvText-8.4 {TextInsert procedure: inserting before selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c select from test 2 @@ -555,9 +535,9 @@ test canvText-8.4 {TextInsert procedure: inserting before selection} -setup { list [.c index test sel.first] [.c index test sel.last] } -result {5 7} test canvText-8.5 {TextInsert procedure: inserting in selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c select from test 2 @@ -566,9 +546,9 @@ test canvText-8.5 {TextInsert procedure: inserting in selection} -setup { list [.c index test sel.first] [.c index test sel.last] } -result {2 7} test canvText-8.6 {TextInsert procedure: inserting after selection} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c select from test 2 @@ -577,9 +557,9 @@ test canvText-8.6 {TextInsert procedure: inserting after selection} -setup { list [.c index test sel.first] [.c index test sel.last] } -result {2 4} test canvText-8.7 {TextInsert procedure: inserting in unselected item} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c select clear @@ -587,9 +567,9 @@ test canvText-8.7 {TextInsert procedure: inserting in unselected item} -setup { .c itemcget test -text } -result {abcdexyzfg} test canvText-8.8 {TextInsert procedure: inserting before cursor} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c icursor test 3 @@ -597,9 +577,9 @@ test canvText-8.8 {TextInsert procedure: inserting before cursor} -setup { .c index test insert } -result {6} test canvText-8.9 {TextInsert procedure: inserting after cursor} -setup { - .c create text 20 20 -tag test - focus .c - .c focus test + .c create text 20 20 -tag test + focus .c + .c focus test } -body { .c itemconfig test -text "abcdefg" .c icursor test 3 @@ -712,7 +692,7 @@ test canvText-9.15 {TextInsert procedure: cursor doesn't move} -body { test canvText-10.1 {TextToPoint procedure} -body { - .c create text 0 0 -tag test + .c create text 0 0 -tag test .c itemconfig test -text 0 -anchor center .c index test @0,0 } -cleanup { @@ -721,22 +701,22 @@ test canvText-10.1 {TextToPoint procedure} -body { test canvText-11.1 {TextToArea procedure} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c itemconfig test -text 0 -anchor center - set res1 [.c find overlapping 0 0 1 1] - set res2 [.c find withtag test] - expr {$res1 eq $res2} + set res1 [.c find overlapping 0 0 1 1] + set res2 [.c find withtag test] + expr {$res1 eq $res2} } -cleanup { - .c delete test + .c delete test } -result 1 test canvText-11.2 {TextToArea procedure} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c itemconfig test -text 0 -anchor center .c find overlapping 1000 1000 1001 1001 } -cleanup { @@ -745,7 +725,7 @@ test canvText-11.2 {TextToArea procedure} -setup { test canvText-12.1 {ScaleText procedure} -body { - .c create text 100 100 -tag test + .c create text 100 100 -tag test .c scale all 50 50 2 2 format {%.6g %.6g} {*}[.c coords test] } -cleanup { @@ -763,61 +743,60 @@ test canvText-13.1 {TranslateText procedure} -body { test canvText-14.1 {GetTextIndex procedure} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { - .c itemconfig test -text "abcdefghijklmno" -anchor nw - .c select from test 5 - .c select to test 8 - .c icursor test 12 - .c coords test 0 0 - + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { + .c itemconfig test -text "abcdefghijklmno" -anchor nw + .c select from test 5 + .c select to test 8 + .c icursor test 12 + .c coords test 0 0 list [.c index test end] [.c index test insert] \ [.c index test sel.first] [.c index test sel.last] \ [.c index test @0,0] \ [.c index test -1] [.c index test 10] [.c index test 100] } -cleanup { - .c delete test + .c delete test } -result {15 12 5 8 0 0 10 15} test canvText-14.2 {GetTextIndex procedure: select error} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c select clear .c index test sel.first } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {selection isn't in item} test canvText-14.3 {GetTextIndex procedure: select error} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c select clear .c index test sel.last } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {selection isn't in item} test canvText-14.4 {GetTextIndex procedure: select error} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c select clear .c index test sel. } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {bad index "sel."} test canvText-14.5 {GetTextIndex procedure: bad int or unknown index} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c index test xyz } -cleanup { - .c delete test + .c delete test } -returnCodes {error} -result {bad index "xyz"} test canvText-14.6 {select clear errors} -setup { .c create text 0 0 -tag test @@ -828,54 +807,51 @@ test canvText-14.6 {select clear errors} -setup { } -returnCodes error -result "wrong \# args: should be \".c select clear\"" test canvText-15.1 {SetTextCursor procedure} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { - .c itemconfig test -text "abcdefghijklmno" -anchor nw + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { + .c itemconfig test -text "abcdefghijklmno" -anchor nw .c itemconfig -text "abcdefg" .c icursor test 3 .c index test insert } -cleanup { - .c delete test + .c delete test } -result {3} - test canvText-16.1 {GetSelText procedure} -setup { - .c create text 0 0 -tag test - focus .c - .c focus test -} -body { + .c create text 0 0 -tag test + focus .c + .c focus test +} -body { .c itemconfig test -text "abcdefghijklmno" -anchor nw .c select from test 5 .c select to test 8 selection get } -cleanup { - .c delete test + .c delete test } -result {fghi} - test canvText-17.1 {TextToPostscript procedure} -setup { .c delete all -} -body { - set font {Courier 12 italic} - set ax [font measure $font 0] - set ay [font metrics $font -linespace] - - set result "/Courier-Oblique findfont [font actual $font -size] scalefont ISOEncode setfont + set result {/Courier-Oblique findfont [font actual $font -size] scalefont ISOEncode setfont 0.000 0.000 0.000 setrgbcolor AdjustColor -100 200 \[ +0 100 200 \[ \[(000)\] \[(000)\] \[(00)\] -] $ay -0.5 0.0 0 false DrawText +\] $ay -0.5 0 0 false DrawText grestore restore showpage %%Trailer end %%EOF -" +} +} -body { + set font {Courier 12 italic} + set ax [font measure $font 0] + set ay [font metrics $font -linespace] .c config -height 300 -highlightthickness 0 -bd 0 update .c create text 100 100 -tags test @@ -883,8 +859,8 @@ end .c itemconfig test -anchor n -fill black set x [.c postscript] set x [string range $x [string first "/Courier-Oblique" $x] end] - expr {$x eq $result} -} -result 1 + expr {$x eq [subst $result] ? "ok" : $x} +} -result ok test canvText-18.1 {bug fix 2525, find enclosed on text with newlines} -setup { destroy .c @@ -898,23 +874,19 @@ test canvText-18.1 {bug fix 2525, find enclosed on text with newlines} -setup { update .c find enclosed 99 99 [expr $x2 + 1] [expr $y2 + 1] } -cleanup { - destroy .c + destroy .c } -result 1 - test canvText-19.1 {patch 1006286, leading space caused wrap under Win32} -setup { destroy .c -} -body { set c [canvas .c -bg black -width 964] pack $c $c delete all - after 1000 "set done 1" ; vwait done - + after 100 "set done 1"; vwait done +} -body { set f {Arial 28 bold} - set s1 { Yeah-ah-ah-ah-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-oh-Yow} set s2 { Yeah ah ah ah oh oh oh oh oh oh oh oh oh oh oh oh oh oh oh oh Yow} - $c create text 21 18 \ -font $f \ -text $s1 \ @@ -922,8 +894,7 @@ test canvText-19.1 {patch 1006286, leading space caused wrap under Win32} -setup -width 922 \ -anchor nw \ -tags tbox1 - eval {$c create rect} [$c bbox tbox1] -outline red - + $c create rect {*}[$c bbox tbox1] -outline red $c create text 21 160 \ -font $f \ -text $s2 \ @@ -931,38 +902,50 @@ test canvText-19.1 {patch 1006286, leading space caused wrap under Win32} -setup -width 922 \ -anchor nw \ -tags tbox2 - eval {$c create rect} [$c bbox tbox2] -outline red - - after 1000 "set done 1" ; vwait done - + $c create rect {*}[$c bbox tbox2] -outline red + after 500 "set done 1" ; vwait done set results [list] - $c select from tbox2 4 $c select to tbox2 8 lappend results [selection get] - $c select from tbox1 4 $c select to tbox1 8 lappend results [selection get] - array set metrics [font metrics $f] set x [expr {21 + [font measure $f " "] \ + ([font measure {Arial 28 bold} "Y"] / 2)}] set y1 [expr {18 + ($metrics(-linespace) / 2)}] set y2 [expr {160 + ($metrics(-linespace) / 2)}] - lappend results [$c index tbox1 @$x,$y1] lappend results [$c index tbox2 @$x,$y2] - - return $results } -cleanup { - destroy .c + destroy .c } -result {{Yeah } Yeah- 4 4} +test canvText-20.1 {angled text bounding box} -setup { + destroy .c + canvas .c + proc transpose {bbox} { + lassign $bbox a b c d + list $b $a $d $c + } +} -body { + .c create text 2 2 -tag t -anchor center -text 0 -font {Helvetica 24} + set bb0 [.c bbox t] + .c itemconf t -angle 90 + set bb1 [.c bbox t] + .c itemconf t -angle 180 + set bb2 [.c bbox t] + .c itemconf t -angle 270 + set bb3 [.c bbox t] + list [expr {$bb0 eq $bb2 ? "ok" : "$bb0,$bb2"}] \ + [expr {$bb1 eq $bb3 ? "ok" : "$bb1,$bb3"}] \ + [expr {$bb0 eq [transpose $bb1] ? "ok" : "$bb0,$bb1"}] \ +} -cleanup { + destroy .c + rename transpose {} +} -result {ok ok ok} # cleanup cleanupTests return - - - diff --git a/unix/tkUnixFont.c b/unix/tkUnixFont.c index 405b19c..b069cd9 100644 --- a/unix/tkUnixFont.c +++ b/unix/tkUnixFont.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixFont.c,v 1.38 2008/11/05 22:20:59 nijtmans Exp $ + * RCS: @(#) $Id: tkUnixFont.c,v 1.39 2008/11/22 18:08:51 dkf Exp $ */ #include "tkUnixInt.h" @@ -139,9 +139,9 @@ typedef struct UnixFont { */ typedef struct EncodingAlias { - const char *realName; /* The real name of the encoding to load if + const char *realName; /* The real name of the encoding to load if * the provided name matched the pattern. */ - const char *aliasPattern; /* Pattern for encoding name, of the form that + const char *aliasPattern; /* Pattern for encoding name, of the form that * is acceptable to Tcl_StringMatch. */ } EncodingAlias; @@ -3018,6 +3018,283 @@ GetEncodingAlias( return name; } +static inline XImage * +GetImageOfText( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + Tk_Font tkfont, /* Font in which characters will be drawn. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + int *realWidthPtr, int *realHeightPtr) +{ + int width, height; + TkFont *fontPtr = (TkFont *) tkfont; + Pixmap bitmap; + GC bitmapGC; + XGCValues values; + XImage *image; + + (void) Tk_MeasureChars(tkfont, source, numBytes, -1, 0, &width); + height = fontPtr->fm.ascent + fontPtr->fm.descent; + + bitmap = Tk_GetPixmap(display, drawable, width, height, 1); + values.graphics_exposures = False; + values.foreground = BlackPixel(display, DefaultScreen(display)); + bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground, + &values); + XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height); + + values.font = Tk_FontId(tkfont); + values.foreground = WhitePixel(display, DefaultScreen(display)); + values.background = BlackPixel(display, DefaultScreen(display)); + XChangeGC(display, bitmapGC, GCFont|GCForeground|GCBackground, &values); + Tk_DrawChars(display, bitmap, bitmapGC, tkfont, source, numBytes, 0, + fontPtr->fm.ascent); + XFreeGC(display, bitmapGC); + + image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes, + ZPixmap); + Tk_FreePixmap(display, bitmap); + + *realWidthPtr = width; + *realHeightPtr = height; + return image; +} + +static inline XImage * +InitDestImage( + Display *display, + Drawable drawable, + int width, + int height, + Pixmap *bitmapPtr) +{ + Pixmap bitmap; + XImage *image; + GC bitmapGC; + XGCValues values; + + bitmap = Tk_GetPixmap(display, drawable, width, height, 1); + values.graphics_exposures = False; + values.foreground = BlackPixel(display, DefaultScreen(display)); + bitmapGC = XCreateGC(display, bitmap, GCGraphicsExposures|GCForeground, + &values); + XFillRectangle(display, bitmap, bitmapGC, 0, 0, width, height); + XFreeGC(display, bitmapGC); + + image = XGetImage(display, bitmap, 0, 0, width, height, AllPlanes, + ZPixmap); + *bitmapPtr = bitmap; + return image; +} + +void +TkpDrawAngledChars( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + double x, double y, + double angle) +{ + if (angle == 0.0) { + Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y); + } else { + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); + int bufHeight, bufWidth, srcWidth, srcHeight, i, j, dx, dy; + Pixmap buf; + XImage *srcImage = GetImageOfText(display, drawable, tkfont, source, + numBytes, &srcWidth, &srcHeight); + XImage *dstImage; + enum {Q0=1,R1,Q1,R2,Q2,R3,Q3} quadrant; + GC bwgc, cpgc; + XGCValues values; + int ascent = ((TkFont *) tkfont)->fm.ascent; + + /* + * First, work out what quadrant we are operating in. We also handle + * the rectilinear rotations as special cases. Conceptually, there's + * also R0 (angle == 0.0) but that has been already handled as a + * special case above. + * + * R1 + * Q1 | Q0 + * | + * R2 ----+---- R0 + * | + * Q2 | Q3 + * R3 + */ + + if (angle < 90.0) { + quadrant = Q0; + } else if (angle == 90.0) { + quadrant = R1; + } else if (angle < 180.0) { + quadrant = Q1; + } else if (angle == 180.0) { + quadrant = R2; + } else if (angle < 270.0) { + quadrant = Q2; + } else if (angle == 270.0) { + quadrant = R3; + } else { + quadrant = Q3; + } + + if (srcImage == NULL) { + return; + } + bufWidth = srcWidth*fabs(cosA) + srcHeight*fabs(sinA); + bufHeight = srcHeight*fabs(cosA) + srcWidth*fabs(sinA); + dstImage = InitDestImage(display, drawable, bufWidth,bufHeight, &buf); + if (dstImage == NULL) { + Tk_FreePixmap(display, buf); + XDestroyImage(srcImage); + return; + } + + /* + * Do the rotation, setting or resetting pixels in the destination + * image dependent on whether the corresponding pixel (after rotation + * to source image space) is set. + */ + + for (i=0 ; i= bufWidth || dy >= bufHeight) { + continue; + } + XPutPixel(dstImage, dx, dy, + XGetPixel(dstImage,dx,dy) | XGetPixel(srcImage,i,j)); + } + } + XDestroyImage(srcImage); + + /* + * Schlep the data back to the Xserver. + */ + + values.function = GXcopy; + values.foreground = WhitePixel(display, DefaultScreen(display)); + values.background = BlackPixel(display, DefaultScreen(display)); + bwgc = XCreateGC(display, buf, GCFunction|GCForeground|GCBackground, + &values); + XPutImage(display, buf, bwgc, dstImage, 0,0, 0,0, bufWidth,bufHeight); + XFreeGC(display, bwgc); + XDestroyImage(dstImage); + + /* + * Calculate where we want to draw the text. + */ + + switch (quadrant) { + case Q0: + dx = x; + dy = y - srcWidth*sinA; + break; + case R1: + dx = x; + dy = y - srcWidth; + break; + case Q1: + dx = x + srcWidth*cosA; + dy = y + srcHeight*cosA - srcWidth*sinA; + break; + case R2: + dx = x - srcWidth; + dy = y - srcHeight; + break; + case Q2: + dx = x + srcWidth*cosA + srcHeight*sinA; + dy = y + srcHeight*cosA; + break; + case R3: + dx = x - srcHeight; + dy = y; + break; + default: + dx = x + srcHeight*sinA; + dy = y; + } + + /* + * Apply a correction to deal with the fact that we aren't told to + * draw from our top-left corner but rather from the left-end of our + * baseline. + */ + + dx -= ascent*sinA; + dy -= ascent*cosA; + + /* + * Transfer the text to the screen. This is done by using it as a mask + * and then drawing through that mask with the original drawing color. + */ + + values.function = GXcopy; + values.fill_style = FillSolid; + values.clip_mask = buf; + values.clip_x_origin = dx; + values.clip_y_origin = dy; + cpgc = XCreateGC(display, drawable, + GCFunction|GCFillStyle|GCClipMask|GCClipXOrigin|GCClipYOrigin, + &values); + XCopyGC(display, gc, GCForeground, cpgc); + XFillRectangle(display, drawable, cpgc, dx, dy, bufWidth, + bufHeight); + XFreeGC(display, cpgc); + + Tk_FreePixmap(display, buf); + return; + } +} + /* * Local Variables: * mode: c diff --git a/unix/tkUnixRFont.c b/unix/tkUnixRFont.c index 0a6be20..00b8095 100644 --- a/unix/tkUnixRFont.c +++ b/unix/tkUnixRFont.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixRFont.c,v 1.26 2008/11/05 22:20:59 nijtmans Exp $ + * RCS: @(#) $Id: tkUnixRFont.c,v 1.27 2008/11/22 18:08:51 dkf Exp $ */ #include "tkUnixInt.h" @@ -18,8 +18,10 @@ typedef struct { XftFont *ftFont; + XftFont *ft0Font; FcPattern *source; FcCharSet *charset; + double angle; } UnixFtFace; typedef struct { @@ -62,13 +64,15 @@ TkpFontPkgInit( static XftFont * GetFont( UnixFtFont *fontPtr, - FcChar32 ucs4) + FcChar32 ucs4, + double angle) { int i; if (ucs4) { for (i = 0; i < fontPtr->nfaces; i++) { FcCharSet *charset = fontPtr->faces[i].charset; + if (charset && FcCharSetHasChar(charset, ucs4)) { break; } @@ -79,34 +83,52 @@ GetFont( } else { i = 0; } - if (!fontPtr->faces[i].ftFont) { - FcPattern *pat = FcFontRenderPrepare(0, - fontPtr->pattern, fontPtr->faces[i].source); - XftFont *ftFont = XftFontOpenPattern(fontPtr->display, pat); + if ((angle == 0.0 && !fontPtr->faces[i].ft0Font) || (angle != 0.0 && + (!fontPtr->faces[i].ftFont || fontPtr->faces[i].angle != angle))){ + FcPattern *pat = FcFontRenderPrepare(0, fontPtr->pattern, + fontPtr->faces[i].source); + double s = sin(angle*PI/180.0), c = cos(angle*PI/180.0); + FcMatrix mat = {c, -s, s, c}; + XftFont *ftFont; + if (angle != 0.0) { + FcPatternAddMatrix(pat, FC_MATRIX, &mat); + } + ftFont = XftFontOpenPattern(fontPtr->display, pat); if (!ftFont) { /* - * The previous call to XftFontOpenPattern() should not fail, - * but sometimes does anyway. Usual cause appears to be - * a misconfigured fontconfig installation; see [Bug 1090382]. - * Try a fallback: + * The previous call to XftFontOpenPattern() should not fail, but + * sometimes does anyway. Usual cause appears to be a + * misconfigured fontconfig installation; see [Bug 1090382]. Try a + * fallback: */ + ftFont = XftFontOpen(fontPtr->display, fontPtr->screen, - FC_FAMILY, FcTypeString, "sans", - FC_SIZE, FcTypeDouble, 12.0, - NULL); + FC_FAMILY, FcTypeString, "sans", + FC_SIZE, FcTypeDouble, 12.0, + FC_MATRIX, FcTypeMatrix, &mat, + NULL); } if (!ftFont) { /* - * The previous call should definitely not fail. - * Impossible to proceed at this point. + * The previous call should definitely not fail. Impossible to + * proceed at this point. */ + Tcl_Panic("Cannot find a usable font."); } - fontPtr->faces[i].ftFont = ftFont; + if (angle == 0.0) { + fontPtr->faces[i].ft0Font = ftFont; + } else { + if (fontPtr->faces[i].ftFont) { + XftFontClose(fontPtr->display, fontPtr->faces[i].ftFont); + } + fontPtr->faces[i].ftFont = ftFont; + fontPtr->faces[i].angle = angle; + } } - return fontPtr->faces[i].ftFont; + return (angle==0.0? fontPtr->faces[i].ft0Font : fontPtr->faces[i].ftFont); } /* @@ -126,10 +148,10 @@ GetTkFontAttributes( int weight, slant, size, pxsize; double ptsize; - (void)XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr); + (void) XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr); if (XftPatternGetDouble(ftFont->pattern, XFT_SIZE, 0, &ptsize) == XftResultMatch) { - size = (int)ptsize; + size = (int) ptsize; } else if (XftPatternGetInteger(ftFont->pattern, XFT_PIXEL_SIZE, 0, &pxsize) == XftResultMatch) { size = -pxsize; @@ -165,7 +187,8 @@ GetTkFontAttributes( * Fill in TkFontMetrics from an XftFont. */ -static void GetTkFontMetrics( +static void +GetTkFontMetrics( XftFont *ftFont, TkFontMetrics *fmPtr) { @@ -222,7 +245,7 @@ InitFont( set = FcFontSort(0, pattern, FcTrue, NULL, &result); if (!set) { FcPatternDestroy(pattern); - ckfree((char *)fontPtr); + ckfree((char *) fontPtr); return NULL; } @@ -237,6 +260,7 @@ InitFont( for (i = 0; i < set->nfont; i++) { fontPtr->faces[i].ftFont = 0; + fontPtr->faces[i].ft0Font = 0; fontPtr->faces[i].source = set->fonts[i]; if (FcPatternGetCharSet(set->fonts[i], FC_CHARSET, 0, &charset) == FcResultMatch) { @@ -244,6 +268,7 @@ InitFont( } else { fontPtr->faces[i].charset = 0; } + fontPtr->faces[i].angle = 0.0; } fontPtr->display = Tk_Display(tkwin); @@ -258,7 +283,8 @@ InitFont( /* * Fill in platform-specific fields of TkFont. */ - ftFont = GetFont(fontPtr, 0); + + ftFont = GetFont(fontPtr, 0, 0.0); fontPtr->font.fid = XLoadFont(Tk_Display(tkwin), "fixed"); GetTkFontAttributes(ftFont, &fontPtr->font.fa); GetTkFontMetrics(ftFont, &fontPtr->font.fm); @@ -272,19 +298,22 @@ FinishedWithFont( { Display *display = fontPtr->display; int i; - Tk_ErrorHandler handler = Tk_CreateErrorHandler(display, -1, -1, -1, NULL, - (ClientData) NULL); + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); for (i = 0; i < fontPtr->nfaces; i++) { if (fontPtr->faces[i].ftFont) { XftFontClose(fontPtr->display, fontPtr->faces[i].ftFont); } + if (fontPtr->faces[i].ft0Font) { + XftFontClose(fontPtr->display, fontPtr->faces[i].ft0Font); + } if (fontPtr->faces[i].charset) { FcCharSetDestroy(fontPtr->faces[i].charset); } } if (fontPtr->faces) { - ckfree((char *)fontPtr->faces); + ckfree((char *) fontPtr->faces); } if (fontPtr->pattern) { FcPatternDestroy(fontPtr->pattern); @@ -432,14 +461,15 @@ TkpGetFontFamilies( resultPtr = Tcl_NewListObj(0, NULL); list = XftListFonts(Tk_Display(tkwin), Tk_ScreenNumber(tkwin), - (char*)0, /* pattern elements */ - XFT_FAMILY, (char*)0); /* fields */ + (char *) 0, /* pattern elements */ + XFT_FAMILY, (char*) 0); /* fields */ for (i = 0; i < list->nfont; i++) { char *family, **familyPtr = &family; + if (XftPatternGetString(list->fonts[i], XFT_FAMILY, 0, familyPtr) - == XftResultMatch) - { + == XftResultMatch) { Tcl_Obj *strPtr = Tcl_NewStringObj(family, -1); + Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); } } @@ -517,7 +547,7 @@ TkpGetFontAttrsForChar( /* Structure describing the logical font */ FcChar32 ucs4 = (FcChar32) c; /* UCS-4 character to map */ - XftFont *ftFont = GetFont(fontPtr, ucs4); + XftFont *ftFont = GetFont(fontPtr, ucs4, 0.0); /* Actual font used to render the character */ GetTkFontAttributes(ftFont, faPtr); @@ -566,7 +596,7 @@ Tk_MeasureChars( Tcl_UniChar unichar; clen = Tcl_UtfToUniChar(source, &unichar); - c = (FcChar32)unichar; + c = (FcChar32) unichar; if (clen <= 0) { /* @@ -592,7 +622,7 @@ Tk_MeasureChars( #if DEBUG_FONTSEL string[len++] = (char) c; #endif /* DEBUG_FONTSEL */ - ftFont = GetFont(fontPtr, c); + ftFont = GetFont(fontPtr, c, 0.0); XftTextExtents32(fontPtr->display, ftFont, &c, 1, &extents); @@ -674,8 +704,8 @@ Tk_DrawChars( DefaultVisual(display, fontPtr->screen), DefaultColormap(display, fontPtr->screen)); } else { - Tk_ErrorHandler handler = Tk_CreateErrorHandler(display, -1, -1, -1, - NULL, (ClientData) NULL); + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); XftDrawChange(fontPtr->ftDraw, drawable); Tk_DeleteErrorHandler(handler); @@ -707,7 +737,7 @@ Tk_DrawChars( source += clen; numBytes -= clen; - ftFont = GetFont(fontPtr, c); + ftFont = GetFont(fontPtr, c, 0.0); if (ftFont) { specs[nspec].font = ftFont; specs[nspec].glyph = XftCharIndex(fontPtr->display, ftFont, c); @@ -729,3 +759,195 @@ Tk_DrawChars( XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec); } } + +void +TkpDrawAngledChars( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + double x, double y, /* Coordinates at which to place origin of + * string when drawing. */ + double angle) /* What angle to put text at, in degrees. */ +{ + const int maxCoord = 0x7FFF;/* Xft coordinates are 16 bit values */ + const int minCoord = -1000; /* Should be good enough... */ + UnixFtFont *fontPtr = (UnixFtFont *) tkfont; + XGCValues values; + XColor xcolor; +#ifdef XFT_HAS_FIXED_ROTATED_PLACEMENT + int clen, nglyph; + FT_UInt glyphs[NUM_SPEC]; + XGlyphInfo metrics; + XftFont *currentFtFont; + int originX, originY; + + if (fontPtr->ftDraw == 0) { +#if DEBUG_FONTSEL + printf("Switch to drawable 0x%x\n", drawable); +#endif /* DEBUG_FONTSEL */ + fontPtr->ftDraw = XftDrawCreate(display, drawable, + DefaultVisual(display, fontPtr->screen), + DefaultColormap(display, fontPtr->screen)); + } else { + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); + + XftDrawChange(fontPtr->ftDraw, drawable); + Tk_DeleteErrorHandler(handler); + } + + XGetGCValues(display, gc, GCForeground, &values); + if (values.foreground != fontPtr->color.pixel) { + xcolor.pixel = values.foreground; + XQueryColor(display, DefaultColormap(display, fontPtr->screen), + &xcolor); + fontPtr->color.color.red = xcolor.red; + fontPtr->color.color.green = xcolor.green; + fontPtr->color.color.blue = xcolor.blue; + fontPtr->color.color.alpha = 0xffff; + fontPtr->color.pixel = values.foreground; + } + + nglyph = 0; + currentFtFont = NULL; + originX = originY = 0; /* lint */ + + while (numBytes > 0 && x <= maxCoord && x >= minCoord && y <= maxCoord + && y >= minCoord) { + XftFont *ftFont; + FcChar32 c; + + clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + if (clen <= 0) { + /* + * This should not happen, but it can. + */ + + return; + } + source += clen; + numBytes -= clen; + + ftFont = GetFont(fontPtr, c, angle); + if (!ftFont) { + continue; + } + + if (ftFont != currentFtFont || nglyph == NUM_SPEC) { + if (nglyph) { + /* + * We pass multiple glyphs at once to enable the code to + * perform better rendering of sub-pixel inter-glyph spacing. + * If only the current Xft implementation could make use of + * this information... but we'll be ready when it does! + */ + + XftDrawGlyphs(fontPtr->ftDraw, &fontPtr->color, currentFtFont, + originX, originY, glyphs, nglyph); + } + originX = (int) floor(x + 0.5); + originY = (int) floor(y + 0.5); + if (nglyph) { + XftGlyphExtents(fontPtr->display, currentFtFont, glyphs, + nglyph, &metrics); + nglyph = 0; + x += metrics.xOff; + y += metrics.yOff; + } + currentFtFont = ftFont; + } + glyphs[nglyph++] = XftCharIndex(fontPtr->display, ftFont, c); + } + if (nglyph) { + XftDrawGlyphs(fontPtr->ftDraw, &fontPtr->color, currentFtFont, + originX, originY, glyphs, nglyph); + } +#else /* !XFT_HAS_FIXED_ROTATED_PLACEMENT */ + int clen, nspec; + XftGlyphFontSpec specs[NUM_SPEC]; + XGlyphInfo metrics; + double sinA = sin(angle * PI/180.0), cosA = cos(angle * PI/180.0); + + if (fontPtr->ftDraw == 0) { +#if DEBUG_FONTSEL + printf("Switch to drawable 0x%x\n", drawable); +#endif /* DEBUG_FONTSEL */ + fontPtr->ftDraw = XftDrawCreate(display, drawable, + DefaultVisual(display, fontPtr->screen), + DefaultColormap(display, fontPtr->screen)); + } else { + Tk_ErrorHandler handler = + Tk_CreateErrorHandler(display, -1, -1, -1, NULL, NULL); + + XftDrawChange(fontPtr->ftDraw, drawable); + Tk_DeleteErrorHandler(handler); + } + XGetGCValues(display, gc, GCForeground, &values); + if (values.foreground != fontPtr->color.pixel) { + xcolor.pixel = values.foreground; + XQueryColor(display, DefaultColormap(display, fontPtr->screen), + &xcolor); + fontPtr->color.color.red = xcolor.red; + fontPtr->color.color.green = xcolor.green; + fontPtr->color.color.blue = xcolor.blue; + fontPtr->color.color.alpha = 0xffff; + fontPtr->color.pixel = values.foreground; + } + nspec = 0; + while (numBytes > 0 && x <= maxCoord && x >= minCoord + && y <= maxCoord && y >= minCoord) { + XftFont *ftFont, *ft0Font; + FcChar32 c; + + clen = FcUtf8ToUcs4((FcChar8 *) source, &c, numBytes); + if (clen <= 0) { + /* + * This should not happen, but it can. + */ + + return; + } + source += clen; + numBytes -= clen; + + ftFont = GetFont(fontPtr, c, angle); + ft0Font = GetFont(fontPtr, c, 0.0); + if (ftFont && ft0Font) { + specs[nspec].font = ftFont; + specs[nspec].glyph = XftCharIndex(fontPtr->display, ftFont, c); + specs[nspec].x = (int) floor(x + 0.5); + specs[nspec].y = (int) floor(y + 0.5); + XftGlyphExtents(fontPtr->display, ft0Font, &specs[nspec].glyph, 1, + &metrics); + x += metrics.xOff*cosA + metrics.yOff*sinA; + y += metrics.yOff*cosA - metrics.xOff*sinA; + nspec++; + if (nspec == NUM_SPEC) { + XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, + specs, nspec); + nspec = 0; + } + } + } + if (nspec) { + XftDrawGlyphFontSpec(fontPtr->ftDraw, &fontPtr->color, specs, nspec); + } +#endif /* XFT_HAS_FIXED_ROTATED_PLACEMENT */ +} + +/* + * Local Variables: + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/win/tkWinFont.c b/win/tkWinFont.c index 755dc04..264acc2 100644 --- a/win/tkWinFont.c +++ b/win/tkWinFont.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinFont.c,v 1.43 2008/11/08 22:52:29 dkf Exp $ + * RCS: @(#) $Id: tkWinFont.c,v 1.44 2008/11/22 18:08:51 dkf Exp $ */ #include "tkWinInt.h" @@ -52,7 +52,7 @@ typedef struct FontFamily { int isSymbolFont; /* Non-zero if this is a symbol font. */ int isWideFont; /* 1 if this is a double-byte font, 0 * otherwise. */ - BOOL (WINAPI *textOutProc)(HDC, int, int, TCHAR *, int); + BOOL (WINAPI *textOutProc)(HDC hdc, int x, int y, TCHAR *str, int len); /* The procedure to use to draw text after it * has been converted from UTF-8 to the * encoding of this font. */ @@ -96,10 +96,12 @@ typedef struct FontFamily { typedef struct SubFont { char **fontMap; /* Pointer to font map from the FontFamily, * cached here to save a dereference. */ - HFONT hFont; /* The specific screen font that will be used + HFONT hFont0; /* The specific screen font that will be used * when displaying/measuring chars belonging * to the FontFamily. */ FontFamily *familyPtr; /* The FontFamily for this SubFont. */ + HFONT hFontAngled; + double angle; } SubFont; /* @@ -125,7 +127,6 @@ typedef struct WinFont { * attributes. Usually points to * staticSubFonts, but may point to malloced * space if there are lots of SubFonts. */ - HWND hwnd; /* Toplevel window of application that owns * this font, used for getting HDC for * offscreen measurements. */ @@ -206,10 +207,11 @@ static void FontMapLoadPage(SubFont *subFontPtr, int row); static int FontMapLookup(SubFont *subFontPtr, int ch); static void FreeFontFamily(FontFamily *familyPtr); static HFONT GetScreenFont(const TkFontAttributes *faPtr, - const char *faceName, int pixelSize); + const char *faceName, int pixelSize, + double angle); static void InitFont(Tk_Window tkwin, HFONT hFont, int overstrike, WinFont *tkFontPtr); -static void InitSubFont(HDC hdc, HFONT hFont, int base, +static inline void InitSubFont(HDC hdc, HFONT hFont, int base, SubFont *subFontPtr); static int CreateNamedSystemLogFont(Tcl_Interp *interp, Tk_Window tkwin, const char* name, @@ -220,12 +222,15 @@ static int LoadFontRanges(HDC hdc, HFONT hFont, USHORT **startCount, USHORT **endCount, int *symbolPtr); static void MultiFontTextOut(HDC hdc, WinFont *fontPtr, - const char *source, int numBytes, int x, int y); + const char *source, int numBytes, int x, int y, + double angle); static void ReleaseFont(WinFont *fontPtr); -static void ReleaseSubFont(SubFont *subFontPtr); +static inline void ReleaseSubFont(SubFont *subFontPtr); static int SeenName(const char *name, Tcl_DString *dsPtr); -static void SwapLong(PULONG p); -static void SwapShort(USHORT *p); +static inline HFONT SelectFont(HDC hdc, WinFont *fontPtr, + SubFont *subFontPtr, double angle); +static inline void SwapLong(PULONG p); +static inline void SwapShort(USHORT *p); static int CALLBACK WinFontCanUseProc(ENUMLOGFONT *lfPtr, NEWTEXTMETRIC *tmPtr, int fontType, LPARAM lParam); @@ -320,13 +325,13 @@ TkpGetNativeFont( /* *--------------------------------------------------------------------------- + * * CreateNamedSystemFont -- * * This function registers a Windows logical font description with the Tk * named font mechanism. * - * Side effects - * + * Side effects: * A new named font is added to the Tk font registry. * *--------------------------------------------------------------------------- @@ -341,7 +346,7 @@ CreateNamedSystemLogFont( { HFONT hFont; int r; - + hFont = CreateFontIndirect(logFontPtr); r = CreateNamedSystemFont(interp, tkwin, name, hFont); DeleteObject((HGDIOBJ)hFont); @@ -350,13 +355,13 @@ CreateNamedSystemLogFont( /* *--------------------------------------------------------------------------- - * CreateNamedSystemFont -- * - * This function registers a Windows font with the Tk - * named font mechanism. + * CreateNamedSystemFont -- * - * Side effects + * This function registers a Windows font with the Tk named font + * mechanism. * + * Side effects: * A new named font is added to the Tk font registry. * *--------------------------------------------------------------------------- @@ -371,7 +376,7 @@ CreateNamedSystemFont( { WinFont winfont; int r; - + TkDeleteNamedFont(NULL, tkwin, name); InitFont(tkwin, hFont, 0, &winfont); r = TkCreateNamedFont(interp, tkwin, name, &winfont.font.fa); @@ -381,10 +386,12 @@ CreateNamedSystemFont( /* *--------------------------------------------------------------------------- + * * TkWinSystemFonts -- * * Create some platform specific named fonts that to give access to the - * system fonts. These are all defined for the Windows desktop parameters. + * system fonts. These are all defined for the Windows desktop + * parameters. * *--------------------------------------------------------------------------- */ @@ -445,7 +452,7 @@ TkWinSetupSystemFonts( hFont = (HFONT) GetStockObject(ANSI_FIXED_FONT); CreateNamedSystemFont(interp, tkwin, "TkFixedFont", hFont); - /* + /* * Setup the remaining standard Tk font names as named fonts. */ @@ -550,7 +557,7 @@ TkpGetFontFromAttributes( ReleaseDC(hwnd, hdc); hFont = GetScreenFont(faPtr, faceName, - TkFontGetPixels(tkwin, faPtr->size)); + TkFontGetPixels(tkwin, faPtr->size), 0.0); if (tkFontPtr == NULL) { fontPtr = (WinFont *) ckalloc(sizeof(WinFont)); } else { @@ -728,7 +735,7 @@ TkpGetFontAttrsForChar( Tk_Window tkwin, /* Window on the font's display */ Tk_Font tkfont, /* Font to query */ Tcl_UniChar c, /* Character of interest */ - TkFontAttributes* faPtr) /* Output: Font attributes */ + TkFontAttributes *faPtr) /* Output: Font attributes */ { WinFont *fontPtr = (WinFont *) tkfont; /* Structure describing the logical font */ @@ -736,12 +743,12 @@ TkpGetFontAttrsForChar( /* GDI device context */ SubFont *lastSubFontPtr = &fontPtr->subFontArray[0]; /* Pointer to subfont array in case - * FindSubFontForChar needs to fix up - * the memory allocation */ - SubFont *thisSubFontPtr = FindSubFontForChar(fontPtr, c, - &lastSubFontPtr); - /* Pointer to the subfont to use for - * the given character */ + * FindSubFontForChar needs to fix up the + * memory allocation */ + SubFont *thisSubFontPtr = + FindSubFontForChar(fontPtr, c, &lastSubFontPtr); + /* Pointer to the subfont to use for the given + * character */ FontFamily *familyPtr = thisSubFontPtr->familyPtr; HFONT oldfont; /* Saved font from the device context */ TEXTMETRIC tm; /* Font metrics of the selected subfont */ @@ -750,7 +757,7 @@ TkpGetFontAttrsForChar( * Get the font attributes. */ - oldfont = SelectObject(hdc, thisSubFontPtr->hFont); + oldfont = SelectObject(hdc, thisSubFontPtr->hFont0); GetTextMetrics(hdc, &tm); SelectObject(hdc, oldfont); ReleaseDC(fontPtr->hwnd, hdc); @@ -828,7 +835,7 @@ Tk_MeasureChars( hdc = GetDC(fontPtr->hwnd); lastSubFontPtr = &fontPtr->subFontArray[0]; - oldFont = SelectObject(hdc, lastSubFontPtr->hFont); + oldFont = SelectObject(hdc, lastSubFontPtr->hFont0); /* * A three step process: @@ -863,7 +870,7 @@ Tk_MeasureChars( lastSubFontPtr = thisSubFontPtr; start = p; - SelectObject(hdc, lastSubFontPtr->hFont); + SelectObject(hdc, lastSubFontPtr->hFont0); } p = next; } @@ -1091,8 +1098,156 @@ Tk_DrawChars( SetROP2(dc, tkpWinRopModes[gc->function]); if ((gc->clip_mask != None) && - ((TkpClipMask*)gc->clip_mask)->type == TKP_CLIP_REGION) { - SelectClipRgn(dc, (HRGN)((TkpClipMask*)gc->clip_mask)->value.region); + ((TkpClipMask *) gc->clip_mask)->type == TKP_CLIP_REGION) { + SelectClipRgn(dc, (HRGN)((TkpClipMask *)gc->clip_mask)->value.region); + } + + if ((gc->fill_style == FillStippled + || gc->fill_style == FillOpaqueStippled) + && gc->stipple != None) { + TkWinDrawable *twdPtr = (TkWinDrawable *) gc->stipple; + HBRUSH oldBrush, stipple; + HBITMAP oldBitmap, bitmap; + HDC dcMem; + TEXTMETRIC tm; + SIZE size; + + if (twdPtr->type != TWD_BITMAP) { + Tcl_Panic("unexpected drawable type in stipple"); + } + + /* + * Select stipple pattern into destination dc. + */ + + dcMem = CreateCompatibleDC(dc); + + stipple = CreatePatternBrush(twdPtr->bitmap.handle); + SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL); + oldBrush = SelectObject(dc, stipple); + + SetTextAlign(dcMem, TA_LEFT | TA_BASELINE); + SetTextColor(dcMem, gc->foreground); + SetBkMode(dcMem, TRANSPARENT); + SetBkColor(dcMem, RGB(0, 0, 0)); + + /* + * Compute the bounding box and create a compatible bitmap. + */ + + GetTextExtentPoint(dcMem, source, numBytes, &size); + GetTextMetrics(dcMem, &tm); + size.cx -= tm.tmOverhang; + bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy); + oldBitmap = SelectObject(dcMem, bitmap); + + /* + * The following code is tricky because fonts are rendered in multiple + * colors. First we draw onto a black background and copy the white + * bits. Then we draw onto a white background and copy the black bits. + * Both the foreground and background bits of the font are ANDed with + * the stipple pattern as they are copied. + */ + + PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS); + MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, 0.0); + BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, + 0, 0, 0xEA02E9); + PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS); + MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, 0.0); + BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, + 0, 0, 0x8A0E06); + + /* + * Destroy the temporary bitmap and restore the device context. + */ + + SelectObject(dcMem, oldBitmap); + DeleteObject(bitmap); + DeleteDC(dcMem); + SelectObject(dc, oldBrush); + DeleteObject(stipple); + } else if (gc->function == GXcopy) { + SetTextAlign(dc, TA_LEFT | TA_BASELINE); + SetTextColor(dc, gc->foreground); + SetBkMode(dc, TRANSPARENT); + MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, 0.0); + } else { + HBITMAP oldBitmap, bitmap; + HDC dcMem; + TEXTMETRIC tm; + SIZE size; + + dcMem = CreateCompatibleDC(dc); + + SetTextAlign(dcMem, TA_LEFT | TA_BASELINE); + SetTextColor(dcMem, gc->foreground); + SetBkMode(dcMem, TRANSPARENT); + SetBkColor(dcMem, RGB(0, 0, 0)); + + /* + * Compute the bounding box and create a compatible bitmap. + */ + + GetTextExtentPoint(dcMem, source, numBytes, &size); + GetTextMetrics(dcMem, &tm); + size.cx -= tm.tmOverhang; + bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy); + oldBitmap = SelectObject(dcMem, bitmap); + + MultiFontTextOut(dcMem, fontPtr, source, numBytes, 0, tm.tmAscent, + 0.0); + BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, + 0, 0, (DWORD) tkpWinBltModes[gc->function]); + + /* + * Destroy the temporary bitmap and restore the device context. + */ + + SelectObject(dcMem, oldBitmap); + DeleteObject(bitmap); + DeleteDC(dcMem); + } + TkWinReleaseDrawableDC(drawable, dc, &state); +} + +void +TkpDrawAngledChars( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + const char *source, /* UTF-8 string to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are not + * stripped out, they will be displayed as + * regular printing characters. */ + int numBytes, /* Number of bytes in string. */ + double x, double y, /* Coordinates at which to place origin of + * string when drawing. */ + double angle) +{ + HDC dc; + WinFont *fontPtr; + TkWinDCState state; + + fontPtr = (WinFont *) gc->font; + display->request++; + + if (drawable == None) { + return; + } + + dc = TkWinGetDrawableDC(display, drawable, &state); + + SetROP2(dc, tkpWinRopModes[gc->function]); + + if ((gc->clip_mask != None) && + ((TkpClipMask *) gc->clip_mask)->type == TKP_CLIP_REGION) { + SelectClipRgn(dc, (HRGN)((TkpClipMask *)gc->clip_mask)->value.region); } if ((gc->fill_style == FillStippled @@ -1143,11 +1298,11 @@ Tk_DrawChars( */ PatBlt(dcMem, 0, 0, size.cx, size.cy, BLACKNESS); - MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); + MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, angle); BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, 0, 0, 0xEA02E9); PatBlt(dcMem, 0, 0, size.cx, size.cy, WHITENESS); - MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); + MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, angle); BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, 0, 0, 0x8A0E06); @@ -1164,7 +1319,7 @@ Tk_DrawChars( SetTextAlign(dc, TA_LEFT | TA_BASELINE); SetTextColor(dc, gc->foreground); SetBkMode(dc, TRANSPARENT); - MultiFontTextOut(dc, fontPtr, source, numBytes, x, y); + MultiFontTextOut(dc, fontPtr, source, numBytes, x, y, angle); } else { HBITMAP oldBitmap, bitmap; HDC dcMem; @@ -1188,7 +1343,8 @@ Tk_DrawChars( bitmap = CreateCompatibleBitmap(dc, size.cx, size.cy); oldBitmap = SelectObject(dcMem, bitmap); - MultiFontTextOut(dcMem, fontPtr, source, numBytes, 0, tm.tmAscent); + MultiFontTextOut(dcMem, fontPtr, source, numBytes, 0, tm.tmAscent, + angle); BitBlt(dc, x, y - tm.tmAscent, size.cx, size.cy, dcMem, 0, 0, (DWORD) tkpWinBltModes[gc->function]); @@ -1243,8 +1399,8 @@ TkpDrawCharsInContext( * drawing. */ { (void) numBytes; /*unused*/ - Tk_DrawChars(display, drawable, gc, tkfont, - source + rangeStart, rangeLength, x, y); + Tk_DrawChars(display, drawable, gc, tkfont, source + rangeStart, + rangeLength, x, y); } /* @@ -1274,8 +1430,9 @@ MultiFontTextOut( * following string. */ const char *source, /* Potentially multilingual UTF-8 string. */ int numBytes, /* Length of string in bytes. */ - int x, int y) /* Coordinates at which to place origin of + int x, int y, /* Coordinates at which to place origin of * string when drawing. */ + double angle) { Tcl_UniChar ch; SIZE size; @@ -1287,7 +1444,7 @@ MultiFontTextOut( TEXTMETRIC tm; lastSubFontPtr = &fontPtr->subFontArray[0]; - oldFont = SelectObject(hdc, lastSubFontPtr->hFont); + oldFont = SelectFont(hdc, fontPtr, lastSubFontPtr, angle); GetTextMetrics(hdc, &tm); end = source + numBytes; @@ -1311,7 +1468,7 @@ MultiFontTextOut( } lastSubFontPtr = thisSubFontPtr; source = p; - SelectObject(hdc, lastSubFontPtr->hFont); + SelectFont(hdc, fontPtr, lastSubFontPtr, angle); GetTextMetrics(hdc, &tm); } p = next; @@ -1327,6 +1484,31 @@ MultiFontTextOut( } SelectObject(hdc, oldFont); } + +static inline HFONT +SelectFont( + HDC hdc, + WinFont *fontPtr, + SubFont *subFontPtr, + double angle) +{ + if (angle == 0.0) { + return SelectObject(hdc, subFontPtr->hFont0); + } else if (angle == subFontPtr->angle) { + return SelectObject(hdc, subFontPtr->hFontAngled); + } else { + if (subFontPtr->hFontAngled) { + DeleteObject(subFontPtr->hFontAngled); + } + subFontPtr->hFontAngled = GetScreenFont(&fontPtr->font.fa, + subFontPtr->familyPtr->faceName, fontPtr->pixelSize, angle); + if (subFontPtr->hFontAngled == NULL) { + return SelectObject(hdc, subFontPtr->hFont0); + } + subFontPtr->angle = angle; + return SelectObject(hdc, subFontPtr->hFontAngled); + } +} /* *--------------------------------------------------------------------------- @@ -1501,7 +1683,7 @@ ReleaseFont( *------------------------------------------------------------------------- */ -static void +static inline void InitSubFont( HDC hdc, /* HDC in which font can be selected. */ HFONT hFont, /* The screen font. */ @@ -1510,9 +1692,11 @@ InitSubFont( SubFont *subFontPtr) /* Filled with SubFont constructed from above * attributes. */ { - subFontPtr->hFont = hFont; + subFontPtr->hFont0 = hFont; subFontPtr->familyPtr = AllocFontFamily(hdc, hFont, base); subFontPtr->fontMap = subFontPtr->familyPtr->fontMap; + subFontPtr->hFontAngled = NULL; + subFontPtr->angle = 0.0; } /* @@ -1532,11 +1716,14 @@ InitSubFont( *--------------------------------------------------------------------------- */ -static void +static inline void ReleaseSubFont( SubFont *subFontPtr) /* The SubFont to delete. */ { - DeleteObject(subFontPtr->hFont); + DeleteObject(subFontPtr->hFont0); + if (subFontPtr->hFontAngled) { + DeleteObject(subFontPtr->hFontAngled); + } FreeFontFamily(subFontPtr->familyPtr); } @@ -2047,7 +2234,8 @@ FontMapLoadPage( if (endCount[j] >= i) { if (startCount[j] <= i) { bitOffset = i & (FONTMAP_BITSPERPAGE - 1); - subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7); + subFontPtr->fontMap[row][bitOffset >> 3] |= + 1 << (bitOffset & 7); } break; } @@ -2236,7 +2424,8 @@ CanUseFallback( * Load this font and see if it has the desired character. */ - hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize); + hFont = GetScreenFont(&fontPtr->font.fa, faceName, fontPtr->pixelSize, + 0.0); InitSubFont(hdc, hFont, 0, &subFont); if (((ch < 256) && (subFont.familyPtr->isSymbolFont)) || (FontMapLookup(&subFont, ch) == 0)) { @@ -2252,9 +2441,9 @@ CanUseFallback( if (fontPtr->numSubFonts >= SUBFONT_SPACE) { SubFont *newPtr; - newPtr = (SubFont *) ckalloc(sizeof(SubFont) - * (fontPtr->numSubFonts + 1)); - memcpy((char *) newPtr, fontPtr->subFontArray, + newPtr = (SubFont *) + ckalloc(sizeof(SubFont) * (fontPtr->numSubFonts + 1)); + memcpy(newPtr, fontPtr->subFontArray, fontPtr->numSubFonts * sizeof(SubFont)); if (fontPtr->subFontArray != fontPtr->staticSubFonts) { ckfree((char *) fontPtr->subFontArray); @@ -2296,8 +2485,10 @@ GetScreenFont( /* Desired font attributes for new HFONT. */ const char *faceName, /* Overrides font family specified in font * attributes. */ - int pixelSize) /* Overrides size specified in font + int pixelSize, /* Overrides size specified in font * attributes. */ + double angle) /* What is the desired orientation of the + * font. */ { Tcl_DString ds; HFONT hFont; @@ -2306,8 +2497,8 @@ GetScreenFont( memset(&lf, 0, sizeof(lf)); lf.lfHeight = -pixelSize; lf.lfWidth = 0; - lf.lfEscapement = 0; - lf.lfOrientation = 0; + lf.lfEscapement = (int) floor(angle * 10 + 0.5); + lf.lfOrientation = (int) floor(angle * 10 + 0.5); lf.lfWeight = (faPtr->weight == TK_FW_NORMAL) ? FW_NORMAL : FW_BOLD; lf.lfItalic = faPtr->slant; lf.lfUnderline = faPtr->underline; @@ -2725,14 +2916,14 @@ LoadFontRanges( *------------------------------------------------------------------------- */ -static void +static inline void SwapShort( PUSHORT p) { *p = (SHORT)(HIBYTE(*p) + (LOBYTE(*p) << 8)); } -static void +static inline void SwapLong( PULONG p) { -- cgit v0.12