Panda3D
 All Classes Functions Variables Enumerations
textAssembler.I
1 // Filename: textAssembler.I
2 // Created by: drose (06Apr04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 
16 ////////////////////////////////////////////////////////////////////
17 // Function: TextAssembler::set_usage_hint
18 // Access: Published
19 // Description: Specifies the UsageHint that will be applied to
20 // generated geometry. The default is UH_static, which
21 // is probably the right setting, but if you know the
22 // TextNode's geometry will have a short lifespan, it
23 // may be better to set it to UH_stream. See
24 // geomEnums.h.
25 ////////////////////////////////////////////////////////////////////
26 INLINE void TextAssembler::
27 set_usage_hint(Geom::UsageHint usage_hint) {
28  _usage_hint = usage_hint;
29 }
30 
31 ////////////////////////////////////////////////////////////////////
32 // Function: TextAssembler::get_usage_hint
33 // Access: Published
34 // Description: Returns the UsageHint that will be applied to
35 // generated geometry. See set_usage_hint().
36 ////////////////////////////////////////////////////////////////////
37 INLINE Geom::UsageHint TextAssembler::
38 get_usage_hint() const {
39  return _usage_hint;
40 }
41 
42 ////////////////////////////////////////////////////////////////////
43 // Function: TextAssembler::set_max_rows
44 // Access: Published
45 // Description: If max_rows is greater than zero, no more than
46 // max_rows will be accepted. Text beyond that will be
47 // truncated.
48 //
49 // Setting this will not truncate text immediately. You
50 // must follow this up with a call to set_wtext() to
51 // truncate the existing text.
52 ////////////////////////////////////////////////////////////////////
53 INLINE void TextAssembler::
54 set_max_rows(int max_rows) {
55  _max_rows = max_rows;
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: TextAssembler::get_max_rows
60 // Access: Published
61 // Description: If max_rows is greater than zero, no more than
62 // max_rows will be accepted. Text beyond that will be
63 // truncated.
64 ////////////////////////////////////////////////////////////////////
65 INLINE int TextAssembler::
66 get_max_rows() const {
67  return _max_rows;
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: TextAssembler::set_dynamic_merge
72 // Access: Published
73 // Description: Sets the dynamic_merge flag. See
74 // TextNode::set_flatten_flags().
75 ////////////////////////////////////////////////////////////////////
76 INLINE void TextAssembler::
77 set_dynamic_merge(bool dynamic_merge) {
78  _dynamic_merge = dynamic_merge;
79 }
80 
81 ////////////////////////////////////////////////////////////////////
82 // Function: TextAssembler::get_dynamic_merge
83 // Access: Published
84 // Description: Returns the dynamic_merge flag. See
85 // TextNode::set_flatten_flags().
86 ////////////////////////////////////////////////////////////////////
87 INLINE bool TextAssembler::
89  return _dynamic_merge;
90 }
91 
92 ////////////////////////////////////////////////////////////////////
93 // Function: TextAssembler::set_multiline_mode
94 // Access: Published
95 // Description: Sets the multiline mode flag. Set the multiline
96 // mode to allow text to wrap. It defaults to true.
97 ////////////////////////////////////////////////////////////////////
98 INLINE void TextAssembler::
99 set_multiline_mode(bool flag) {
100  _multiline_mode = flag;
101 }
102 
103 ////////////////////////////////////////////////////////////////////
104 // Function: TextAssembler::get_multiline_mode
105 // Access: Published
106 // Description: Returns the multline_mode flag. See
107 // TextNode::set_multiline_mode().
108 ////////////////////////////////////////////////////////////////////
109 INLINE bool TextAssembler::
111  return _multiline_mode;
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: TextAssembler::set_properties
116 // Access: Published
117 // Description: Specifies the default TextProperties that are applied
118 // to the text in the absence of any nested property
119 // change sequences.
120 ////////////////////////////////////////////////////////////////////
121 INLINE void TextAssembler::
122 set_properties(const TextProperties &properties) {
123  _initial_cprops = new ComputedProperties(properties);
124 }
125 
126 ////////////////////////////////////////////////////////////////////
127 // Function: TextAssembler::get_properties
128 // Access: Published
129 // Description: Returns the default TextProperties that are applied
130 // to the text in the absence of any nested property
131 // change sequences.
132 ////////////////////////////////////////////////////////////////////
133 INLINE const TextProperties &TextAssembler::
134 get_properties() const {
135  return _initial_cprops->_properties;
136 }
137 
138 ////////////////////////////////////////////////////////////////////
139 // Function: TextAssembler::get_ul
140 // Access: Published
141 // Description: Returns the upper-left corner of the assembled text,
142 // in 2-d text coordinates.
143 ////////////////////////////////////////////////////////////////////
144 INLINE const LVector2 &TextAssembler::
145 get_ul() const {
146  return _ul;
147 }
148 
149 ////////////////////////////////////////////////////////////////////
150 // Function: TextAssembler::get_lr
151 // Access: Published
152 // Description: Returns the lower-right corner of the assembled text,
153 // in 2-d text coordinates.
154 ////////////////////////////////////////////////////////////////////
155 INLINE const LVector2 &TextAssembler::
156 get_lr() const {
157  return _lr;
158 }
159 
160 ////////////////////////////////////////////////////////////////////
161 // Function: TextAssembler::calc_r
162 // Access: Published
163 // Description: Computes the row index of the nth character or
164 // graphic object in the text and returns it.
165 //
166 // If the nth character is not a normal printable
167 // character with a position in the wordwrapped string,
168 // returns -1 (for instance, a soft-hyphen character, or
169 // a newline character, may not have a corresponding
170 // position).
171 ////////////////////////////////////////////////////////////////////
172 int TextAssembler::
173 calc_r(int n) const {
174  int r, c;
175  if (calc_r_c(r, c, n)) {
176  return r;
177  }
178  return -1;
179 }
180 
181 ////////////////////////////////////////////////////////////////////
182 // Function: TextAssembler::calc_c
183 // Access: Published
184 // Description: Computes the column index of the nth character or
185 // graphic object in the text and returns it.
186 //
187 // If the nth character is not a normal printable
188 // character with a position in the wordwrapped string,
189 // returns -1 (for instance, a soft-hyphen character, or
190 // a newline character, may not have a corresponding
191 // position).
192 ////////////////////////////////////////////////////////////////////
193 int TextAssembler::
194 calc_c(int n) const {
195  int r, c;
196  if (calc_r_c(r, c, n)) {
197  return c;
198  }
199  return -1;
200 }
201 
202 ////////////////////////////////////////////////////////////////////
203 // Function: TextAssembler::get_num_characters
204 // Access: Published
205 // Description: Returns the number of characters of text, before
206 // wordwrapping.
207 ////////////////////////////////////////////////////////////////////
208 INLINE int TextAssembler::
210  return _text_string.size();
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: TextAssembler::get_character
215 // Access: Published
216 // Description: Returns the character at the indicated position in
217 // the pre-wordwrapped string. If the object at this
218 // position is a graphic object instead of a character,
219 // returns 0.
220 ////////////////////////////////////////////////////////////////////
221 INLINE wchar_t TextAssembler::
222 get_character(int n) const {
223  nassertr(n >= 0 && n < (int)_text_string.size(), 0);
224  return _text_string[n]._character;
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: TextAssembler::get_graphic
229 // Access: Published
230 // Description: Returns the graphic object at the indicated position
231 // in the pre-wordwrapped string. If the object at this
232 // position is a character instead of a graphic object,
233 // returns NULL.
234 ////////////////////////////////////////////////////////////////////
235 INLINE const TextGraphic *TextAssembler::
236 get_graphic(int n) const {
237  nassertr(n >= 0 && n < (int)_text_string.size(), 0);
238  return _text_string[n]._graphic;
239 }
240 
241 ////////////////////////////////////////////////////////////////////
242 // Function: TextAssembler::get_properties
243 // Access: Published
244 // Description: Returns the TextProperties in effect for the object
245 // at the indicated position in the pre-wordwrapped
246 // string.
247 ////////////////////////////////////////////////////////////////////
248 INLINE const TextProperties &TextAssembler::
249 get_properties(int n) const {
250  nassertr(n >= 0 && n < (int)_text_string.size(), *(new TextProperties()));
251  return _text_string[n]._cprops->_properties;
252 }
253 
254 ////////////////////////////////////////////////////////////////////
255 // Function: TextAssembler::get_width
256 // Access: Published
257 // Description: Returns the width of the character or object at the
258 // indicated position in the pre-wordwrapped string.
259 ////////////////////////////////////////////////////////////////////
260 INLINE PN_stdfloat TextAssembler::
261 get_width(int n) const {
262  nassertr(n >= 0 && n < (int)_text_string.size(), 0.0f);
263 
264  return calc_width(_text_string[n]);
265 }
266 
267 ////////////////////////////////////////////////////////////////////
268 // Function: TextAssembler::get_num_rows
269 // Access: Published
270 // Description: Returns the number of rows of text after it has all
271 // been wordwrapped and assembled.
272 ////////////////////////////////////////////////////////////////////
273 INLINE int TextAssembler::
274 get_num_rows() const {
275  return _text_block.size();
276 }
277 
278 ////////////////////////////////////////////////////////////////////
279 // Function: TextAssembler::get_num_cols
280 // Access: Published
281 // Description: Returns the number of characters and/or graphic
282 // objects in the nth row.
283 ////////////////////////////////////////////////////////////////////
284 INLINE int TextAssembler::
285 get_num_cols(int r) const {
286  nassertr(r >= 0 && r <= (int)_text_block.size(), 0);
287  if (r == (int)_text_block.size()) {
288  return 0;
289  }
290  return _text_block[r]._string.size();
291 }
292 
293 ////////////////////////////////////////////////////////////////////
294 // Function: TextAssembler::get_character
295 // Access: Published
296 // Description: Returns the character at the indicated position in
297 // the indicated row. If the object at this position is
298 // a graphic object instead of a character, returns 0.
299 ////////////////////////////////////////////////////////////////////
300 INLINE wchar_t TextAssembler::
301 get_character(int r, int c) const {
302  nassertr(r >= 0 && r < (int)_text_block.size(), 0);
303  nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0);
304  return _text_block[r]._string[c]._character;
305 }
306 
307 ////////////////////////////////////////////////////////////////////
308 // Function: TextAssembler::get_graphic
309 // Access: Published
310 // Description: Returns the graphic object at the indicated position
311 // in the indicated row. If the object at this position
312 // is a character instead of a graphic object, returns
313 // NULL.
314 ////////////////////////////////////////////////////////////////////
315 INLINE const TextGraphic *TextAssembler::
316 get_graphic(int r, int c) const {
317  nassertr(r >= 0 && r < (int)_text_block.size(), 0);
318  nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0);
319  return _text_block[r]._string[c]._graphic;
320 }
321 
322 ////////////////////////////////////////////////////////////////////
323 // Function: TextAssembler::get_properties
324 // Access: Published
325 // Description: Returns the TextProperties in effect for the object
326 // at the indicated position in the indicated row.
327 ////////////////////////////////////////////////////////////////////
328 INLINE const TextProperties &TextAssembler::
329 get_properties(int r, int c) const {
330  nassertr(r >= 0 && r < (int)_text_block.size(), *(new TextProperties()));
331  nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), *(new TextProperties()));
332  return _text_block[r]._string[c]._cprops->_properties;
333 }
334 
335 ////////////////////////////////////////////////////////////////////
336 // Function: TextAssembler::get_width
337 // Access: Published
338 // Description: Returns the width of the character or object at the
339 // indicated position in the indicated row.
340 ////////////////////////////////////////////////////////////////////
341 INLINE PN_stdfloat TextAssembler::
342 get_width(int r, int c) const {
343  nassertr(r >= 0 && r < (int)_text_block.size(), 0.0f);
344  nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0.0f);
345 
346  return calc_width(_text_block[r]._string[c]);
347 }
348 
349 ////////////////////////////////////////////////////////////////////
350 // Function: TextAssembler::get_ypos
351 // Access: Published
352 // Description: Returns the y position of the origin of all of the
353 // characters or graphic objects in the indicated row.
354 //
355 // It is legal for r to exceed the index number of the
356 // last row by 1. The value of c is presently ignored.
357 ////////////////////////////////////////////////////////////////////
358 INLINE PN_stdfloat TextAssembler::
359 get_ypos(int r, int) const {
360  nassertr(r >= 0 && r <= (int)_text_block.size(), 0.0f);
361  if (r == (int)_text_block.size()) {
362  return _next_row_ypos;
363  } else {
364  return _text_block[r]._ypos;
365  }
366 }
367 
368 ////////////////////////////////////////////////////////////////////
369 // Function: TextAssembler::calc_width
370 // Access: Private, Static
371 // Description: Returns the width of a single character, according to
372 // its associated font.
373 ////////////////////////////////////////////////////////////////////
374 INLINE PN_stdfloat TextAssembler::
375 calc_width(const TextCharacter &tch) {
376  if (tch._graphic != (TextGraphic *)NULL) {
377  return calc_width(tch._graphic, tch._cprops->_properties);
378  } else {
379  return calc_width(tch._character, tch._cprops->_properties);
380  }
381 }
382 
383 ////////////////////////////////////////////////////////////////////
384 // Function: TextAssembler::TextCharacter::Constructor
385 // Access: Public
386 // Description:
387 ////////////////////////////////////////////////////////////////////
388 INLINE TextAssembler::TextCharacter::
389 TextCharacter(wchar_t character,
390  TextAssembler::ComputedProperties *cprops) :
391  _character(character),
392  _graphic(NULL),
393  _cprops(cprops)
394 {
395 }
396 
397 ////////////////////////////////////////////////////////////////////
398 // Function: TextAssembler::TextCharacter::Constructor
399 // Access: Public
400 // Description:
401 ////////////////////////////////////////////////////////////////////
402 INLINE TextAssembler::TextCharacter::
403 TextCharacter(const TextGraphic *graphic, const wstring &graphic_wname,
404  TextAssembler::ComputedProperties *cprops) :
405  _character(0),
406  _graphic(graphic),
407  _graphic_wname(graphic_wname),
408  _cprops(cprops)
409 {
410 }
411 
412 ////////////////////////////////////////////////////////////////////
413 // Function: TextAssembler::TextCharacter::Copy Constructor
414 // Access: Public
415 // Description:
416 ////////////////////////////////////////////////////////////////////
417 INLINE TextAssembler::TextCharacter::
418 TextCharacter(const TextAssembler::TextCharacter &copy) :
419  _character(copy._character),
420  _graphic(copy._graphic),
421  _graphic_wname(copy._graphic_wname),
422  _cprops(copy._cprops)
423 {
424 }
425 
426 ////////////////////////////////////////////////////////////////////
427 // Function: TextAssembler::TextCharacter::Copy Assignment
428 // Access: Public
429 // Description:
430 ////////////////////////////////////////////////////////////////////
431 INLINE void TextAssembler::TextCharacter::
432 operator = (const TextAssembler::TextCharacter &copy) {
433  _character = copy._character;
434  _graphic = copy._graphic;
435  _graphic_wname = copy._graphic_wname;
436  _cprops = copy._cprops;
437 }
438 
439 ////////////////////////////////////////////////////////////////////
440 // Function: TextAssembler::TextRow::Constructor
441 // Access: Public
442 // Description:
443 ////////////////////////////////////////////////////////////////////
444 INLINE TextAssembler::TextRow::
445 TextRow(int row_start) :
446  _row_start(row_start),
447  _got_soft_hyphens(false),
448  _xpos(0.0f),
449  _ypos(0.0f)
450 {
451 }
452 
453 ////////////////////////////////////////////////////////////////////
454 // Function: TextAssembler::TextRow::Copy Constructor
455 // Access: Public
456 // Description:
457 ////////////////////////////////////////////////////////////////////
458 INLINE TextAssembler::TextRow::
459 TextRow(const TextAssembler::TextRow &copy) :
460  _string(copy._string),
461  _row_start(copy._row_start),
462  _got_soft_hyphens(copy._got_soft_hyphens),
463  _xpos(copy._xpos),
464  _ypos(copy._ypos),
465  _eol_cprops(copy._eol_cprops)
466 {
467 }
468 
469 ////////////////////////////////////////////////////////////////////
470 // Function: TextAssembler::TextRow::Copy Assignment
471 // Access: Public
472 // Description:
473 ////////////////////////////////////////////////////////////////////
474 INLINE void TextAssembler::TextRow::
475 operator = (const TextAssembler::TextRow &copy) {
476  _string = copy._string;
477  _row_start = copy._row_start;
478  _got_soft_hyphens = copy._got_soft_hyphens;
479  _xpos = copy._xpos;
480  _ypos = copy._ypos;
481  _eol_cprops = copy._eol_cprops;
482 }
483 
484 ////////////////////////////////////////////////////////////////////
485 // Function: TextAssembler::ComputedProperties::Constructor
486 // Access: Public
487 // Description:
488 ////////////////////////////////////////////////////////////////////
489 INLINE TextAssembler::ComputedProperties::
490 ComputedProperties(const TextProperties &orig_properties) :
491  _based_on(NULL),
492  _depth(0),
493  _properties(orig_properties)
494 {
495 }
496 
497 ////////////////////////////////////////////////////////////////////
498 // Function: TextAssembler::ComputedProperties::Constructor
499 // Access: Public
500 // Description:
501 ////////////////////////////////////////////////////////////////////
502 INLINE TextAssembler::ComputedProperties::
503 ComputedProperties(ComputedProperties *based_on, const wstring &wname,
504  TextEncoder *encoder) :
505  _based_on(based_on),
506  _depth(_based_on->_depth + 1),
507  _wname(wname),
508  _properties(based_on->_properties)
509 {
510  TextPropertiesManager *manager =
512 
513  // Now we have to encode the wstring into a string, for lookup
514  // in the TextPropertiesManager.
515  string name = encoder->encode_wtext(wname);
516 
517  const TextProperties *named_props = manager->get_properties_ptr(name);
518  if (named_props != (TextProperties *)NULL) {
519  _properties.add_properties(*named_props);
520  } else {
521  text_cat.warning()
522  << "Unknown TextProperties: " << name << "\n";
523  }
524 }
525 
526 
527 ////////////////////////////////////////////////////////////////////
528 // Function: TextAssembler::GlyphPlacement::add_piece
529 // Access: Public
530 // Description: Adds a piece of the glyph, consisting of a single
531 // Geom and an associated RenderState. Typically, a
532 // glyph will have exactly one piece; there will only be
533 // multiple pieces in the case of cheesy accent marks or
534 // ligatures.
535 ////////////////////////////////////////////////////////////////////
536 INLINE void TextAssembler::GlyphPlacement::
537 add_piece(Geom *geom, const RenderState *state) {
538  Piece piece;
539  piece._geom = geom;
540  piece._state = state;
541  _pieces.push_back(piece);
542 }
543 
544 ////////////////////////////////////////////////////////////////////
545 // Function: TextAssembler::GeomCollectorKey::Constructor
546 // Access: Public
547 // Description:
548 ////////////////////////////////////////////////////////////////////
549 INLINE TextAssembler::GeomCollectorKey::
550 GeomCollectorKey(const RenderState *state, const GeomVertexFormat *format) :
551  _state(state),
552  _format(format)
553 {
554 }
555 
556 ////////////////////////////////////////////////////////////////////
557 // Function: TextAssembler::GeomCollectorKey::operator <
558 // Access: Public
559 // Description:
560 ////////////////////////////////////////////////////////////////////
561 INLINE bool TextAssembler::GeomCollectorKey::
562 operator < (const TextAssembler::GeomCollectorKey &other) const {
563  if (_state != other._state) {
564  return _state < other._state;
565  }
566  return _format < other._format;
567 }
568 
569 ////////////////////////////////////////////////////////////////////
570 // Function: TextAssembler::GeomCollector::count_geom
571 // Access: Public
572 // Description: If the indicated Geom is a GeomTextGlyph, increments
573 // its reference count and adds it into this geom. This
574 // is necessary to keep references to outstanding
575 // glyphs, so we know when it's safe to recycle
576 // no-longer-used glyphs.
577 //
578 // If the indicated Geom is an ordinary Geom, does
579 // nothing.
580 ////////////////////////////////////////////////////////////////////
581 INLINE void TextAssembler::GeomCollector::
582 count_geom(const Geom *geom) {
583 #ifdef HAVE_FREETYPE
584  _geom->count_geom(geom);
585 #endif
586 }
int get_num_characters() const
Returns the number of characters of text, before wordwrapping.
int get_num_cols(int r) const
Returns the number of characters and/or graphic objects in the nth row.
int get_num_rows() const
Returns the number of rows of text after it has all been wordwrapped and assembled.
void add_properties(const TextProperties &other)
Sets any properties that are explicitly specified in other on this object.
This class can be used to convert text between multiple representations, e.g.
Definition: textEncoder.h:37
bool get_multiline_mode() const
Returns the multline_mode flag.
const TextProperties & get_properties() const
Returns the default TextProperties that are applied to the text in the absence of any nested property...
string encode_wtext(const wstring &wtext) const
Encodes a wide-text string into a single-char string, according to the current encoding.
Definition: textEncoder.I:557
wchar_t get_character(int n) const
Returns the character at the indicated position in the pre-wordwrapped string.
int calc_r(int n) const
Computes the row index of the nth character or graphic object in the text and returns it...
int get_max_rows() const
If max_rows is greater than zero, no more than max_rows will be accepted.
Definition: textAssembler.I:66
void set_properties(const TextProperties &properties)
Specifies the default TextProperties that are applied to the text in the absence of any nested proper...
void set_multiline_mode(bool flag)
Sets the multiline mode flag.
Definition: textAssembler.I:99
static TextPropertiesManager * get_global_ptr()
Returns the pointer to the global TextPropertiesManager object.
const LVector2 & get_lr() const
Returns the lower-right corner of the assembled text, in 2-d text coordinates.
const LVector2 & get_ul() const
Returns the upper-left corner of the assembled text, in 2-d text coordinates.
static PN_stdfloat calc_width(wchar_t character, const TextProperties &properties)
Returns the width of a single character, according to its associated font.
Geom::UsageHint get_usage_hint() const
Returns the UsageHint that will be applied to generated geometry.
Definition: textAssembler.I:38
A container for geometry primitives.
Definition: geom.h:58
const TextProperties * get_properties_ptr(const string &name)
Returns a pointer to the TextProperties with the indicated name, or NULL if there is no properties wi...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
PN_stdfloat get_width(int n) const
Returns the width of the character or object at the indicated position in the pre-wordwrapped string...
void set_max_rows(int max_rows)
If max_rows is greater than zero, no more than max_rows will be accepted.
Definition: textAssembler.I:54
This is a two-component vector offset.
Definition: lvector2.h:91
const TextGraphic * get_graphic(int n) const
Returns the graphic object at the indicated position in the pre-wordwrapped string.
This defines the set of visual properties that may be assigned to the individual characters of the te...
void set_usage_hint(Geom::UsageHint usage_hint)
Specifies the UsageHint that will be applied to generated geometry.
Definition: textAssembler.I:27
PN_stdfloat get_ypos(int r, int c) const
Returns the y position of the origin of all of the characters or graphic objects in the indicated row...
This defines all of the TextProperties structures that might be referenced by name from an embedded t...
This defines a special model that has been constructed for the purposes of embedding an arbitrary gra...
Definition: textGraphic.h:43
void set_dynamic_merge(bool dynamic_merge)
Sets the dynamic_merge flag.
Definition: textAssembler.I:77
bool get_dynamic_merge() const
Returns the dynamic_merge flag.
Definition: textAssembler.I:88
bool calc_r_c(int &r, int &c, int n) const
Computes the row and column index of the nth character or graphic object in the text.
int calc_c(int n) const
Computes the column index of the nth character or graphic object in the text and returns it...