@@ -73,6 +73,44 @@ def test_create(self):
7373 self .assertRaises (tkinter .TclError , font .Font , root = self .root ,
7474 name = 'testfont' , font = ('Times' , 10 ))
7575
76+ def test_create_from_named_font (self ):
77+ # gh-143990: a font created from a named font copies its configured
78+ # options, preserving a size specified in pixels (a negative size).
79+ sizetype = int if self .wantobjects else str
80+ named = font .Font (root = self .root , name = 'my named font' , # name with spaces
81+ family = 'Times' , size = - 20 , weight = 'bold' )
82+ # The source is the name of a named font or a Font representing one.
83+ for source in ['my named font' , named ]:
84+ with self .subTest (source = source ):
85+ f = font .Font (root = self .root , font = source )
86+ self .assertEqual (f .cget ('size' ), sizetype (- 20 ))
87+ self .assertEqual (f .actual ('family' ), named .actual ('family' ))
88+ self .assertEqual (f .actual ('weight' ), 'bold' )
89+ # Explicit options still override the copied settings.
90+ f = font .Font (root = self .root , font = named , size = 30 )
91+ self .assertEqual (f .cget ('size' ), sizetype (30 ))
92+
93+ def test_create_from_description (self ):
94+ # gh-143990: a font created from a font description is resolved via
95+ # "font actual", so a size in pixels (negative) becomes a size in points.
96+ descriptions = [
97+ ('Times' , - 20 ), # tuple
98+ ('Times' , - 20 , 'bold' ), # tuple with a style
99+ 'Times -20' , # string
100+ 'Times -20 bold' , # string with a style
101+ '{Times New Roman} -20' , # string, family with spaces
102+ # a Font wrapping a description, as a tuple and as a string
103+ font .Font (root = self .root , font = ('Times' , - 20 ), exists = True ),
104+ font .Font (root = self .root , font = 'Times -20' , exists = True ),
105+ ]
106+ for desc in descriptions :
107+ with self .subTest (font = desc ):
108+ f = font .Font (root = self .root , font = desc )
109+ # resolved as if the description were wrapped by exists=True
110+ wrapped = font .Font (root = self .root , font = desc , exists = True )
111+ self .assertEqual (f .actual (), wrapped .actual ())
112+ self .assertGreater (int (f .cget ('size' )), 0 ) # pixels -> points
113+
76114 def test_existing (self ):
77115 sizetype = int if self .wantobjects else str
78116
@@ -109,16 +147,19 @@ def test_existing(self):
109147 self .assertRaises (TypeError , font .Font , root = self .root , exists = True )
110148
111149 def test_copy (self ):
112- f = font .Font (root = self .root , family = 'Times' , size = 10 , weight = 'bold' )
150+ # size=-20 (pixels): copy() copies the configured options, so the
151+ # size is preserved rather than resolved (gh-143990).
152+ f = font .Font (root = self .root , family = 'Times' , size = - 20 , weight = 'bold' )
113153 copied = f .copy ()
114154 self .assertIsInstance (copied , font .Font )
115155 self .assertIsNot (copied , f )
116156 self .assertNotEqual (copied .name , f .name )
117157 self .assertEqual (copied .actual (), f .actual ())
118- # The copy is independent of the original.
119158 sizetype = int if self .wantobjects else str
159+ self .assertEqual (copied .cget ('size' ), sizetype (- 20 ))
160+ # The copy is independent of the original.
120161 copied .configure (size = 20 )
121- self .assertEqual (f .cget ('size' ), sizetype (10 ))
162+ self .assertEqual (f .cget ('size' ), sizetype (- 20 ))
122163 self .assertEqual (copied .cget ('size' ), sizetype (20 ))
123164 self .assertRaises (TypeError , f .copy , 'x' )
124165
0 commit comments