1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 //! This module contains conversion helpers between Servo and Gecko types
6 //! Ideally, it would be in geckolib itself, but coherence
7 //! forces us to keep the traits and implementations here
8 
9 #![allow(unsafe_code)]
10 
11 use app_units::Au;
12 use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible};
13 use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetLayerImageImageValue};
14 use gecko_bindings::bindings::{Gecko_InitializeImageCropRect, Gecko_SetImageElement};
15 use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
16 use gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
17 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
18 use std::f32::consts::PI;
19 use stylesheets::{Origin, RulesMutateError};
20 use values::computed::{Angle, CalcLengthOrPercentage, ComputedImageUrl, Gradient, Image};
21 use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto, Percentage, TextAlign};
22 use values::generics::box_::VerticalAlign;
23 use values::generics::grid::{TrackListValue, TrackSize};
24 use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
25 use values::generics::rect::Rect;
26 
27 impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue28     fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
29         let has_percentage = other.percentage.is_some();
30         nsStyleCoord_CalcValue {
31             mLength: other.unclamped_length().to_i32_au(),
32             mPercent: other.percentage.map_or(0., |p| p.0),
33             mHasPercent: has_percentage,
34         }
35     }
36 }
37 
38 impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
from(other: nsStyleCoord_CalcValue) -> CalcLengthOrPercentage39     fn from(other: nsStyleCoord_CalcValue) -> CalcLengthOrPercentage {
40         let percentage = if other.mHasPercent {
41             Some(Percentage(other.mPercent))
42         } else {
43             None
44         };
45         Self::new(Au(other.mLength).into(), percentage)
46     }
47 }
48 
49 impl From<LengthOrPercentage> for nsStyleCoord_CalcValue {
from(other: LengthOrPercentage) -> nsStyleCoord_CalcValue50     fn from(other: LengthOrPercentage) -> nsStyleCoord_CalcValue {
51         match other {
52             LengthOrPercentage::Length(px) => {
53                 nsStyleCoord_CalcValue {
54                     mLength: px.to_i32_au(),
55                     mPercent: 0.0,
56                     mHasPercent: false,
57                 }
58             },
59             LengthOrPercentage::Percentage(pc) => {
60                 nsStyleCoord_CalcValue {
61                     mLength: 0,
62                     mPercent: pc.0,
63                     mHasPercent: true,
64                 }
65             },
66             LengthOrPercentage::Calc(calc) => calc.into(),
67         }
68     }
69 }
70 
71 impl LengthOrPercentageOrAuto {
72     /// Convert this value in an appropriate `nsStyleCoord::CalcValue`.
to_calc_value(&self) -> Option<nsStyleCoord_CalcValue>73     pub fn to_calc_value(&self) -> Option<nsStyleCoord_CalcValue> {
74         match *self {
75             LengthOrPercentageOrAuto::Length(px) => {
76                 Some(nsStyleCoord_CalcValue {
77                     mLength: px.to_i32_au(),
78                     mPercent: 0.0,
79                     mHasPercent: false,
80                 })
81             },
82             LengthOrPercentageOrAuto::Percentage(pc) => {
83                 Some(nsStyleCoord_CalcValue {
84                     mLength: 0,
85                     mPercent: pc.0,
86                     mHasPercent: true,
87                 })
88             },
89             LengthOrPercentageOrAuto::Calc(calc) => Some(calc.into()),
90             LengthOrPercentageOrAuto::Auto => None,
91         }
92     }
93 }
94 
95 impl From<nsStyleCoord_CalcValue> for LengthOrPercentage {
from(other: nsStyleCoord_CalcValue) -> LengthOrPercentage96     fn from(other: nsStyleCoord_CalcValue) -> LengthOrPercentage {
97         match (other.mHasPercent, other.mLength) {
98             (false, _) => LengthOrPercentage::Length(Au(other.mLength).into()),
99             (true, 0) => LengthOrPercentage::Percentage(Percentage(other.mPercent)),
100             _ => LengthOrPercentage::Calc(other.into()),
101         }
102     }
103 }
104 
105 impl From<nsStyleCoord_CalcValue> for LengthOrPercentageOrAuto {
from(other: nsStyleCoord_CalcValue) -> LengthOrPercentageOrAuto106     fn from(other: nsStyleCoord_CalcValue) -> LengthOrPercentageOrAuto {
107         match (other.mHasPercent, other.mLength) {
108             (false, _) => LengthOrPercentageOrAuto::Length(Au(other.mLength).into()),
109             (true, 0) => LengthOrPercentageOrAuto::Percentage(Percentage(other.mPercent)),
110             _ => LengthOrPercentageOrAuto::Calc(other.into()),
111         }
112     }
113 }
114 
115 impl From<Angle> for CoordDataValue {
from(reference: Angle) -> Self116     fn from(reference: Angle) -> Self {
117         match reference {
118             Angle::Deg(val) => CoordDataValue::Degree(val),
119             Angle::Grad(val) => CoordDataValue::Grad(val),
120             Angle::Rad(val) => CoordDataValue::Radian(val),
121             Angle::Turn(val) => CoordDataValue::Turn(val),
122         }
123     }
124 }
125 
126 impl Angle {
127     /// Converts Angle struct into (value, unit) pair.
to_gecko_values(&self) -> (f32, nsCSSUnit)128     pub fn to_gecko_values(&self) -> (f32, nsCSSUnit) {
129         match *self {
130             Angle::Deg(val) => (val, nsCSSUnit::eCSSUnit_Degree),
131             Angle::Grad(val) => (val, nsCSSUnit::eCSSUnit_Grad),
132             Angle::Rad(val) => (val, nsCSSUnit::eCSSUnit_Radian),
133             Angle::Turn(val) => (val, nsCSSUnit::eCSSUnit_Turn),
134         }
135     }
136 
137     /// Converts gecko (value, unit) pair into Angle struct
from_gecko_values(value: f32, unit: nsCSSUnit) -> Angle138     pub fn from_gecko_values(value: f32, unit: nsCSSUnit) -> Angle {
139         match unit {
140             nsCSSUnit::eCSSUnit_Degree => Angle::Deg(value),
141             nsCSSUnit::eCSSUnit_Grad => Angle::Grad(value),
142             nsCSSUnit::eCSSUnit_Radian => Angle::Rad(value),
143             nsCSSUnit::eCSSUnit_Turn => Angle::Turn(value),
144             _ => panic!("Unexpected unit for angle"),
145         }
146     }
147 }
148 
149 impl nsStyleImage {
150     /// Set a given Servo `Image` value into this `nsStyleImage`.
set(&mut self, image: Image)151     pub fn set(&mut self, image: Image) {
152         match image {
153             GenericImage::Gradient(boxed_gradient) => {
154                 self.set_gradient(*boxed_gradient)
155             },
156             GenericImage::Url(ref url) => {
157                 unsafe {
158                     Gecko_SetLayerImageImageValue(self, url.image_value.get());
159                 }
160             },
161             GenericImage::Rect(ref image_rect) => {
162                 unsafe {
163                     Gecko_SetLayerImageImageValue(self, image_rect.url.image_value.get());
164                     Gecko_InitializeImageCropRect(self);
165 
166                     // Set CropRect
167                     let ref mut rect = *self.mCropRect.mPtr;
168                     image_rect.top.to_gecko_style_coord(&mut rect.data_at_mut(0));
169                     image_rect.right.to_gecko_style_coord(&mut rect.data_at_mut(1));
170                     image_rect.bottom.to_gecko_style_coord(&mut rect.data_at_mut(2));
171                     image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
172                 }
173             }
174             GenericImage::Element(ref element) => {
175                 unsafe {
176                     Gecko_SetImageElement(self, element.as_ptr());
177                 }
178             }
179         }
180     }
181 
set_gradient(&mut self, gradient: Gradient)182     fn set_gradient(&mut self, gradient: Gradient) {
183         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
184         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
185         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
186         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
187         use gecko_bindings::structs::nsStyleCoord;
188         use values::computed::image::LineDirection;
189         use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
190         use values::specified::position::{X, Y};
191 
192         let stop_count = gradient.items.len();
193         if stop_count >= ::std::u32::MAX as usize {
194             warn!("stylo: Prevented overflow due to too many gradient stops");
195             return;
196         }
197 
198         let gecko_gradient = match gradient.kind {
199             GradientKind::Linear(direction) => {
200                 let gecko_gradient = unsafe {
201                     Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
202                                          NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
203                                          gradient.repeating,
204                                          gradient.compat_mode != CompatMode::Modern,
205                                          gradient.compat_mode == CompatMode::Moz,
206                                          stop_count as u32)
207                 };
208 
209                 match direction {
210                     LineDirection::Angle(angle) => {
211                         // PI radians (180deg) is ignored because it is the default value.
212                         if angle.radians() != PI {
213                             unsafe {
214                                 (*gecko_gradient).mAngle.set(angle);
215                             }
216                         }
217                     },
218                     LineDirection::Horizontal(x) => {
219                         let x = match x {
220                             X::Left => 0.0,
221                             X::Right => 1.0,
222                         };
223 
224                         unsafe {
225                             (*gecko_gradient).mBgPosX
226                                              .set_value(CoordDataValue::Percent(x));
227                             (*gecko_gradient).mBgPosY
228                                              .set_value(CoordDataValue::Percent(0.5));
229                         }
230                     },
231                     LineDirection::Vertical(y) => {
232                         // Although bottom is the default value, we can not ignore
233                         // it here, because the rendering code of Gecko relies on
234                         // this to behave correctly for legacy mode.
235                         let y = match y {
236                             Y::Top => 0.0,
237                             Y::Bottom => 1.0,
238                         };
239                         unsafe {
240                             (*gecko_gradient).mBgPosX
241                                                 .set_value(CoordDataValue::Percent(0.5));
242                             (*gecko_gradient).mBgPosY
243                                                 .set_value(CoordDataValue::Percent(y));
244                         }
245                     },
246                     LineDirection::Corner(horiz, vert) => {
247                         let percent_x = match horiz {
248                             X::Left => 0.0,
249                             X::Right => 1.0,
250                         };
251                         let percent_y = match vert {
252                             Y::Top => 0.0,
253                             Y::Bottom => 1.0,
254                         };
255 
256                         unsafe {
257                             (*gecko_gradient).mBgPosX
258                                              .set_value(CoordDataValue::Percent(percent_x));
259                             (*gecko_gradient).mBgPosY
260                                              .set_value(CoordDataValue::Percent(percent_y));
261                         }
262                     },
263                     #[cfg(feature = "gecko")]
264                     LineDirection::MozPosition(position, angle) => {
265                         unsafe {
266                             if let Some(position) = position {
267                                 (*gecko_gradient).mBgPosX.set(position.horizontal);
268                                 (*gecko_gradient).mBgPosY.set(position.vertical);
269                             }
270                             if let Some(angle) = angle {
271                                 (*gecko_gradient).mAngle.set(angle);
272                             }
273                         }
274                     },
275                 }
276                 gecko_gradient
277             },
278             GradientKind::Radial(shape, position, angle) => {
279                 let keyword_to_gecko_size = |keyword| {
280                     match keyword {
281                         ShapeExtent::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
282                         ShapeExtent::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE,
283                         ShapeExtent::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER,
284                         ShapeExtent::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
285                         ShapeExtent::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
286                         ShapeExtent::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
287                     }
288                 };
289                 let (gecko_shape, gecko_size) = match shape {
290                     EndingShape::Circle(ref circle) => {
291                         let size = match *circle {
292                             Circle::Extent(extent) => {
293                                 keyword_to_gecko_size(extent)
294                             },
295                             _ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
296                         };
297                         (NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8)
298                     },
299                     EndingShape::Ellipse(ref ellipse) => {
300                         let size = match *ellipse {
301                             Ellipse::Extent(extent) => {
302                                 keyword_to_gecko_size(extent)
303                             },
304                             _ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
305                         };
306                         (NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8, size as u8)
307                     }
308                 };
309 
310                 let gecko_gradient = unsafe {
311                     Gecko_CreateGradient(gecko_shape,
312                                          gecko_size,
313                                          gradient.repeating,
314                                          gradient.compat_mode == CompatMode::Moz,
315                                          gradient.compat_mode == CompatMode::Moz,
316                                          stop_count as u32)
317                 };
318 
319                 // Clear mBgPos field and set mAngle if angle is set. Otherwise clear it.
320                 unsafe {
321                     if let Some(angle) = angle {
322                         (*gecko_gradient).mAngle.set(angle);
323                     }
324                 }
325 
326                 // Setting radius values depending shape
327                 match shape {
328                     EndingShape::Circle(Circle::Radius(length)) => {
329                         unsafe {
330                             let au = length.to_i32_au();
331                             (*gecko_gradient).mRadiusX.set_value(CoordDataValue::Coord(au));
332                             (*gecko_gradient).mRadiusY.set_value(CoordDataValue::Coord(au));
333                         }
334                     },
335                     EndingShape::Ellipse(Ellipse::Radii(x, y)) => {
336                         unsafe {
337                             (*gecko_gradient).mRadiusX.set(x);
338                             (*gecko_gradient).mRadiusY.set(y);
339                         }
340                     },
341                     _ => {},
342                 }
343                 unsafe {
344                     (*gecko_gradient).mBgPosX.set(position.horizontal);
345                     (*gecko_gradient).mBgPosY.set(position.vertical);
346                 }
347 
348                 gecko_gradient
349             },
350         };
351 
352         for (index, item) in gradient.items.iter().enumerate() {
353             // NB: stops are guaranteed to be none in the gecko side by
354             // default.
355 
356             let gecko_stop = unsafe {
357                 &mut (*gecko_gradient).mStops[index]
358             };
359             let mut coord = nsStyleCoord::null();
360 
361             match *item {
362                 GradientItem::ColorStop(ref stop) => {
363                     gecko_stop.mColor = convert_rgba_to_nscolor(&stop.color);
364                     gecko_stop.mIsInterpolationHint = false;
365                     coord.set(stop.position);
366                 },
367                 GradientItem::InterpolationHint(hint) => {
368                     gecko_stop.mIsInterpolationHint = true;
369                     coord.set(Some(hint));
370                 }
371             }
372 
373             gecko_stop.mLocation.move_from(coord);
374         }
375 
376         unsafe {
377             Gecko_SetGradientImageValue(self, gecko_gradient);
378         }
379     }
380 
381     /// Converts into Image.
into_image(self: &nsStyleImage) -> Option<Image>382     pub unsafe fn into_image(self: &nsStyleImage) -> Option<Image> {
383         use gecko_bindings::bindings::Gecko_GetImageElement;
384         use gecko_bindings::structs::nsStyleImageType;
385         use values::computed::{NumberOrPercentage, MozImageRect};
386 
387         match self.mType {
388             nsStyleImageType::eStyleImageType_Null => {
389                 None
390             },
391             nsStyleImageType::eStyleImageType_Image => {
392                 let url = self.get_image_url();
393                 if self.mCropRect.mPtr.is_null() {
394                     Some(GenericImage::Url(url))
395                 } else {
396                     let ref rect = *self.mCropRect.mPtr;
397                     match (NumberOrPercentage::from_gecko_style_coord(&rect.data_at(0)),
398                            NumberOrPercentage::from_gecko_style_coord(&rect.data_at(1)),
399                            NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)),
400                            NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3))) {
401                         (Some(top), Some(right), Some(bottom), Some(left)) =>
402                             Some(GenericImage::Rect(Box::new(MozImageRect { url, top, right, bottom, left } ))),
403                         _ => {
404                             debug_assert!(false, "mCropRect could not convert to NumberOrPercentage");
405                             None
406                         }
407                     }
408                 }
409             },
410             nsStyleImageType::eStyleImageType_Gradient => {
411                 Some(GenericImage::Gradient(self.get_gradient()))
412             },
413             nsStyleImageType::eStyleImageType_Element => {
414                 use gecko_string_cache::Atom;
415                 let atom = Gecko_GetImageElement(self);
416                 Some(GenericImage::Element(Atom::from(atom)))
417             },
418             _ => panic!("Unexpected image type")
419         }
420     }
421 
get_image_url(self: &nsStyleImage) -> ComputedImageUrl422     unsafe fn get_image_url(self: &nsStyleImage) -> ComputedImageUrl {
423         use gecko_bindings::bindings::Gecko_GetURLValue;
424         let url_value = Gecko_GetURLValue(self);
425         ComputedImageUrl::from_url_value_data(url_value.as_ref().unwrap())
426             .expect("Could not convert to ComputedUrl")
427     }
428 
get_gradient(self: &nsStyleImage) -> Box<Gradient>429     unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> {
430         use gecko::values::convert_nscolor_to_rgba;
431         use gecko_bindings::bindings::Gecko_GetGradientImageValue;
432         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
433         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
434         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
435         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
436         use values::computed::{Length, LengthOrPercentage};
437         use values::computed::image::LineDirection;
438         use values::computed::position::Position;
439         use values::generics::image::{ColorStop, CompatMode, Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
440         use values::specified::position::{X, Y};
441 
442         let gecko_gradient = Gecko_GetGradientImageValue(self).as_ref().unwrap();
443         let angle = Angle::from_gecko_style_coord(&gecko_gradient.mAngle);
444         let horizontal_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosX);
445         let vertical_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosY);
446 
447         let kind = match gecko_gradient.mShape as u32 {
448             NS_STYLE_GRADIENT_SHAPE_LINEAR => {
449                 let line_direction = match (angle, horizontal_style, vertical_style) {
450                     (Some(a), None, None) => LineDirection::Angle(a),
451                     (None, Some(horizontal), Some(vertical)) => {
452                         let horizontal_as_corner = match horizontal {
453                             LengthOrPercentage::Percentage(percentage) => {
454                                 if percentage.0 == 0.0 {
455                                     Some(X::Left)
456                                 } else if percentage.0 == 1.0 {
457                                     Some(X::Right)
458                                 } else {
459                                     None
460                                 }
461                             },
462                             _ => None
463                         };
464                         let vertical_as_corner = match vertical {
465                             LengthOrPercentage::Percentage(percentage) => {
466                                 if percentage.0 == 0.0 {
467                                     Some(Y::Top)
468                                 } else if percentage.0 == 1.0 {
469                                     Some(Y::Bottom)
470                                 } else {
471                                     None
472                                 }
473                             },
474                             _ => None
475                         };
476 
477                         match (horizontal_as_corner, vertical_as_corner) {
478                             (Some(hc), Some(vc)) => LineDirection::Corner(hc, vc),
479                             _ => LineDirection::MozPosition(
480                                      Some(Position { horizontal, vertical }), None)
481                         }
482                     },
483                     (Some(_), Some(horizontal), Some(vertical)) =>
484                         LineDirection::MozPosition(
485                             Some(Position { horizontal, vertical }), angle),
486                     _ => {
487                         debug_assert!(horizontal_style.is_none() && vertical_style.is_none(),
488                                       "Unexpected linear gradient direction");
489                         LineDirection::MozPosition(None, None)
490                     }
491                 };
492                 GradientKind::Linear(line_direction)
493             },
494             _ => {
495                 let gecko_size_to_keyword = |gecko_size| {
496                     match gecko_size {
497                         NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE => ShapeExtent::ClosestSide,
498                         NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE => ShapeExtent::FarthestSide,
499                         NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER => ShapeExtent::ClosestCorner,
500                         NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER => ShapeExtent::FarthestCorner,
501                         // FIXME: We should support ShapeExtent::Contain and ShapeExtent::Cover.
502                         // But we can't choose those yet since Gecko does not support both values.
503                         // https://bugzilla.mozilla.org/show_bug.cgi?id=1217664
504                         _ => panic!("Found unexpected gecko_size"),
505                     }
506                 };
507 
508                 let shape = match gecko_gradient.mShape as u32 {
509                     NS_STYLE_GRADIENT_SHAPE_CIRCULAR => {
510                         let circle = match gecko_gradient.mSize as u32 {
511                             NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
512                                 let radius = Length::from_gecko_style_coord(&gecko_gradient.mRadiusX)
513                                     .expect("mRadiusX could not convert to Length");
514                                 debug_assert_eq!(radius,
515                                                  Length::from_gecko_style_coord(&gecko_gradient.mRadiusY).unwrap());
516                                 Circle::Radius(radius)
517                             },
518                             size => Circle::Extent(gecko_size_to_keyword(size))
519                         };
520                         EndingShape::Circle(circle)
521                     },
522                     NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL => {
523                         let length_percentage_keyword = match gecko_gradient.mSize as u32 {
524                             NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
525                                 match (LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusX),
526                                        LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusY)) {
527                                     (Some(x), Some(y)) => Ellipse::Radii(x, y),
528                                     _ => {
529                                         debug_assert!(false,
530                                                       "mRadiusX, mRadiusY could not convert to LengthOrPercentage");
531                                         Ellipse::Radii(LengthOrPercentage::zero(),
532                                                        LengthOrPercentage::zero())
533                                     }
534                                 }
535                             },
536                             size => Ellipse::Extent(gecko_size_to_keyword(size))
537                         };
538                         EndingShape::Ellipse(length_percentage_keyword)
539                     },
540                     _ => panic!("Found unexpected mShape"),
541                 };
542 
543                 let position = match (horizontal_style, vertical_style) {
544                     (Some(horizontal), Some(vertical)) => Position { horizontal, vertical },
545                     _ => {
546                         debug_assert!(false,
547                                       "mRadiusX, mRadiusY could not convert to LengthOrPercentage");
548                         Position {
549                             horizontal: LengthOrPercentage::zero(),
550                             vertical: LengthOrPercentage::zero()
551                         }
552                     }
553                 };
554 
555                 GradientKind::Radial(shape, position, angle)
556             }
557         };
558 
559         let items = gecko_gradient.mStops.iter().map(|ref stop| {
560             if stop.mIsInterpolationHint {
561                 GradientItem::InterpolationHint(
562                     LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
563                         .expect("mLocation could not convert to LengthOrPercentage")
564                 )
565             } else {
566                 GradientItem::ColorStop(ColorStop {
567                     color: convert_nscolor_to_rgba(stop.mColor),
568                     position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
569                 })
570             }
571         }).collect();
572 
573         let compat_mode =
574             if gecko_gradient.mMozLegacySyntax {
575                 CompatMode::Moz
576             } else if gecko_gradient.mLegacySyntax {
577                 CompatMode::WebKit
578             } else {
579                 CompatMode::Modern
580             };
581 
582         Box::new(Gradient { items, repeating: gecko_gradient.mRepeating, kind, compat_mode })
583     }
584 }
585 
586 pub mod basic_shape {
587     //! Conversions from and to CSS shape representations.
588 
589     use gecko::values::GeckoStyleCoordConvertible;
590     use gecko_bindings::structs;
591     use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule};
592     use gecko_bindings::structs::{StyleGeometryBox, StyleShapeSource, StyleShapeSourceType};
593     use gecko_bindings::structs::{nsStyleCoord, nsStyleCorners};
594     use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue};
595     use std::borrow::Borrow;
596     use values::computed::ComputedUrl;
597     use values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape, ShapeRadius};
598     use values::computed::border::{BorderCornerRadius, BorderRadius};
599     use values::computed::length::LengthOrPercentage;
600     use values::computed::position;
601     use values::generics::basic_shape::{BasicShape as GenericBasicShape, InsetRect, Polygon};
602     use values::generics::basic_shape::{Circle, Ellipse, FillRule};
603     use values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
604     use values::generics::border::BorderRadius as GenericBorderRadius;
605     use values::generics::rect::Rect;
606 
607     impl StyleShapeSource {
608         /// Convert StyleShapeSource to ShapeSource except URL and Image
609         /// types.
into_shape_source<ReferenceBox, ImageOrUrl>( &self ) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>> where ReferenceBox: From<StyleGeometryBox>610         fn into_shape_source<ReferenceBox, ImageOrUrl>(
611             &self
612         ) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>>
613         where
614             ReferenceBox: From<StyleGeometryBox>
615         {
616             match self.mType {
617                 StyleShapeSourceType::None => Some(ShapeSource::None),
618                 StyleShapeSourceType::Box => Some(ShapeSource::Box(self.mReferenceBox.into())),
619                 StyleShapeSourceType::Shape => {
620                     let other_shape = unsafe { &*self.mBasicShape.mPtr };
621                     let shape = other_shape.into();
622                     let reference_box = if self.mReferenceBox == StyleGeometryBox::NoBox {
623                         None
624                     } else {
625                         Some(self.mReferenceBox.into())
626                     };
627                     Some(ShapeSource::Shape(shape, reference_box))
628                 },
629                 StyleShapeSourceType::URL | StyleShapeSourceType::Image => None,
630             }
631         }
632     }
633 
634     impl<'a> From<&'a StyleShapeSource> for ClippingShape
635     {
from(other: &'a StyleShapeSource) -> Self636         fn from(other: &'a StyleShapeSource) -> Self {
637             match other.mType {
638                 StyleShapeSourceType::URL => {
639                     unsafe {
640                         let shape_image = &*other.mShapeImage.mPtr;
641                         let other_url = &(**shape_image.__bindgen_anon_1.mURLValue.as_ref());
642                         let url = ComputedUrl::from_url_value_data(&other_url._base).unwrap();
643                         ShapeSource::ImageOrUrl(url)
644                     }
645                 },
646                 StyleShapeSourceType::Image => {
647                     unreachable!("ClippingShape doesn't support Image!");
648                 }
649                 _ => other.into_shape_source().expect("Couldn't convert to StyleSource!")
650             }
651         }
652     }
653 
654     impl<'a> From<&'a StyleShapeSource> for FloatAreaShape
655     {
from(other: &'a StyleShapeSource) -> Self656         fn from(other: &'a StyleShapeSource) -> Self {
657             match other.mType {
658                 StyleShapeSourceType::URL => {
659                     unreachable!("FloatAreaShape doesn't support URL!");
660                 },
661                 StyleShapeSourceType::Image => {
662                     unsafe {
663                         let shape_image = &*other.mShapeImage.mPtr;
664                         let image = shape_image.into_image().expect("Cannot convert to Image");
665                         ShapeSource::ImageOrUrl(image)
666                     }
667                 }
668                 _ => other.into_shape_source().expect("Couldn't convert to StyleSource!")
669             }
670         }
671     }
672 
673     impl<'a> From<&'a StyleBasicShape> for BasicShape {
from(other: &'a StyleBasicShape) -> Self674         fn from(other: &'a StyleBasicShape) -> Self {
675             match other.mType {
676                 StyleBasicShapeType::Inset => {
677                     let t = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[0]);
678                     let r = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[1]);
679                     let b = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[2]);
680                     let l = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[3]);
681                     let round = (&other.mRadius).into();
682                     let rect = Rect::new(
683                         t.expect("inset() offset should be a length, percentage, or calc value"),
684                         r.expect("inset() offset should be a length, percentage, or calc value"),
685                         b.expect("inset() offset should be a length, percentage, or calc value"),
686                         l.expect("inset() offset should be a length, percentage, or calc value"),
687                     );
688                     GenericBasicShape::Inset(InsetRect {
689                         rect: rect,
690                         round: Some(round),
691                     })
692                 }
693                 StyleBasicShapeType::Circle => {
694                     GenericBasicShape::Circle(Circle {
695                         radius: (&other.mCoordinates[0]).into(),
696                         position: (&other.mPosition).into()
697                     })
698                 }
699                 StyleBasicShapeType::Ellipse => {
700                     GenericBasicShape::Ellipse(Ellipse {
701                         semiaxis_x: (&other.mCoordinates[0]).into(),
702                         semiaxis_y: (&other.mCoordinates[1]).into(),
703                         position: (&other.mPosition).into()
704                     })
705                 }
706                 StyleBasicShapeType::Polygon => {
707                     let fill_rule = if other.mFillRule == StyleFillRule::Evenodd {
708                         FillRule::Evenodd
709                     } else {
710                         FillRule::Nonzero
711                     };
712                     let mut coords = Vec::with_capacity(other.mCoordinates.len() / 2);
713                     for i in 0..(other.mCoordinates.len() / 2) {
714                         let x = 2 * i;
715                         let y = x + 1;
716                         coords.push((LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x])
717                                     .expect("polygon() coordinate should be a length, percentage, or calc value"),
718                                 LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y])
719                                     .expect("polygon() coordinate should be a length, percentage, or calc value")
720                             ))
721                     }
722                     GenericBasicShape::Polygon(Polygon {
723                         fill: fill_rule,
724                         coordinates: coords,
725                     })
726                 }
727             }
728         }
729     }
730 
731     impl<'a> From<&'a nsStyleCorners> for BorderRadius {
from(other: &'a nsStyleCorners) -> Self732         fn from(other: &'a nsStyleCorners) -> Self {
733             let get_corner = |index| {
734                 BorderCornerRadius::new(
735                     LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
736                         .expect("<border-radius> should be a length, percentage, or calc value"),
737                     LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
738                         .expect("<border-radius> should be a length, percentage, or calc value"))
739             };
740 
741             GenericBorderRadius {
742                 top_left: get_corner(0),
743                 top_right: get_corner(2),
744                 bottom_right: get_corner(4),
745                 bottom_left: get_corner(6),
746             }
747         }
748     }
749 
750     // Can't be a From impl since we need to set an existing
751     // nsStyleCorners, not create a new one
752     impl BorderRadius {
753         /// Set this `BorderRadius` into a given `nsStyleCoord`.
set_corners(&self, other: &mut nsStyleCorners)754         pub fn set_corners(&self, other: &mut nsStyleCorners) {
755             let mut set_corner = |field: &BorderCornerRadius, index| {
756                 field.0.width().to_gecko_style_coord(&mut other.data_at_mut(index));
757                 field.0.height().to_gecko_style_coord(&mut other.data_at_mut(index + 1));
758             };
759             set_corner(&self.top_left, 0);
760             set_corner(&self.top_right, 2);
761             set_corner(&self.bottom_right, 4);
762             set_corner(&self.bottom_left, 6);
763         }
764     }
765 
766     /// We use None for a nonexistant radius, but Gecko uses (0 0 0 0 / 0 0 0 0)
set_corners_from_radius(radius: Option<BorderRadius>, other: &mut nsStyleCorners)767     pub fn set_corners_from_radius(radius: Option<BorderRadius>, other: &mut nsStyleCorners) {
768         if let Some(radius) = radius {
769             radius.set_corners(other);
770         } else {
771             for i in 0..8 {
772                 other.data_at_mut(i).set_value(CoordDataValue::Coord(0));
773             }
774         }
775     }
776 
777     // Can't be a From impl since we need to set an existing
778     // Position, not create a new one
779     impl From<position::Position> for structs::Position {
from(other: position::Position) -> Self780         fn from(other: position::Position) -> Self {
781             structs::Position {
782                 mXPosition: other.horizontal.into(),
783                 mYPosition: other.vertical.into()
784             }
785         }
786     }
787 
788     impl<'a> From<&'a nsStyleCoord> for ShapeRadius {
from(other: &'a nsStyleCoord) -> Self789         fn from(other: &'a nsStyleCoord) -> Self {
790             let other = other.borrow();
791             ShapeRadius::from_gecko_style_coord(other)
792                 .expect("<shape-radius> should be a length, percentage, calc, or keyword value")
793         }
794     }
795 
796     impl<'a> From<&'a structs::Position> for position::Position {
from(other: &'a structs::Position) -> Self797         fn from(other: &'a structs::Position) -> Self {
798             position::Position {
799                 horizontal: other.mXPosition.into(),
800                 vertical: other.mYPosition.into(),
801             }
802         }
803     }
804 
805     impl From<ShapeBox> for StyleGeometryBox {
from(reference: ShapeBox) -> Self806         fn from(reference: ShapeBox) -> Self {
807             use gecko_bindings::structs::StyleGeometryBox::*;
808             match reference {
809                 ShapeBox::ContentBox => ContentBox,
810                 ShapeBox::PaddingBox => PaddingBox,
811                 ShapeBox::BorderBox => BorderBox,
812                 ShapeBox::MarginBox => MarginBox,
813             }
814         }
815     }
816 
817     impl From<GeometryBox> for StyleGeometryBox {
from(reference: GeometryBox) -> Self818         fn from(reference: GeometryBox) -> Self {
819             use gecko_bindings::structs::StyleGeometryBox::*;
820             match reference {
821                 GeometryBox::ShapeBox(shape_box) => From::from(shape_box),
822                 GeometryBox::FillBox => FillBox,
823                 GeometryBox::StrokeBox => StrokeBox,
824                 GeometryBox::ViewBox => ViewBox,
825             }
826         }
827     }
828 
829     // Will panic on NoBox
830     // Ideally these would be implemented on Option<T>,
831     // but coherence doesn't like that and TryFrom isn't stable
832     impl From<StyleGeometryBox> for GeometryBox {
from(reference: StyleGeometryBox) -> Self833         fn from(reference: StyleGeometryBox) -> Self {
834             use gecko_bindings::structs::StyleGeometryBox::*;
835             match reference {
836                 ContentBox => GeometryBox::ShapeBox(ShapeBox::ContentBox),
837                 PaddingBox => GeometryBox::ShapeBox(ShapeBox::PaddingBox),
838                 BorderBox => GeometryBox::ShapeBox(ShapeBox::BorderBox),
839                 MarginBox => GeometryBox::ShapeBox(ShapeBox::MarginBox),
840                 FillBox => GeometryBox::FillBox,
841                 StrokeBox => GeometryBox::StrokeBox,
842                 ViewBox => GeometryBox::ViewBox,
843                 _ => panic!("Unexpected StyleGeometryBox while converting to GeometryBox"),
844             }
845         }
846     }
847 
848     impl From<StyleGeometryBox> for ShapeBox {
from(reference: StyleGeometryBox) -> Self849         fn from(reference: StyleGeometryBox) -> Self {
850             use gecko_bindings::structs::StyleGeometryBox::*;
851             match reference {
852                 ContentBox => ShapeBox::ContentBox,
853                 PaddingBox => ShapeBox::PaddingBox,
854                 BorderBox => ShapeBox::BorderBox,
855                 MarginBox => ShapeBox::MarginBox,
856                 _ => panic!("Unexpected StyleGeometryBox while converting to ShapeBox"),
857             }
858         }
859     }
860 }
861 
862 impl From<RulesMutateError> for nsresult {
from(other: RulesMutateError) -> Self863     fn from(other: RulesMutateError) -> Self {
864         match other {
865             RulesMutateError::Syntax => nsresult::NS_ERROR_DOM_SYNTAX_ERR,
866             RulesMutateError::IndexSize => nsresult::NS_ERROR_DOM_INDEX_SIZE_ERR,
867             RulesMutateError::HierarchyRequest => nsresult::NS_ERROR_DOM_HIERARCHY_REQUEST_ERR,
868             RulesMutateError::InvalidState => nsresult::NS_ERROR_DOM_INVALID_STATE_ERR,
869         }
870     }
871 }
872 
873 impl From<Origin> for SheetType {
from(other: Origin) -> Self874     fn from(other: Origin) -> Self {
875         match other {
876             Origin::UserAgent => SheetType::Agent,
877             Origin::Author => SheetType::Doc,
878             Origin::User => SheetType::User,
879         }
880     }
881 }
882 
883 impl TrackSize<LengthOrPercentage> {
884     /// Return TrackSize from given two nsStyleCoord
from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self885     pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
886         use gecko_bindings::structs::root::nsStyleUnit;
887         use values::computed::length::LengthOrPercentage;
888         use values::generics::grid::{TrackBreadth, TrackSize};
889 
890         if gecko_min.unit() == nsStyleUnit::eStyleUnit_None {
891             debug_assert!(gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord ||
892                           gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent ||
893                           gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc);
894             return TrackSize::FitContent(LengthOrPercentage::from_gecko_style_coord(gecko_max)
895                                          .expect("gecko_max could not convert to LengthOrPercentage"));
896         }
897 
898         let min = TrackBreadth::from_gecko_style_coord(gecko_min)
899             .expect("gecko_min could not convert to TrackBreadth");
900         let max = TrackBreadth::from_gecko_style_coord(gecko_max)
901             .expect("gecko_max could not convert to TrackBreadth");
902         if min == max {
903             TrackSize::Breadth(max)
904         } else {
905             TrackSize::Minmax(min, max)
906         }
907     }
908 
909     /// Save TrackSize to given gecko fields.
to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T)910     pub fn to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T) {
911         use values::generics::grid::TrackSize;
912 
913         match *self {
914             TrackSize::FitContent(ref lop) => {
915                 // Gecko sets min value to None and max value to the actual value in fit-content
916                 // https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8221
917                 gecko_min.set_value(CoordDataValue::None);
918                 lop.to_gecko_style_coord(gecko_max);
919             },
920             TrackSize::Breadth(ref breadth) => {
921                 // Set the value to both fields if there's one breadth value
922                 // https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8230
923                 breadth.to_gecko_style_coord(gecko_min);
924                 breadth.to_gecko_style_coord(gecko_max);
925             },
926             TrackSize::Minmax(ref min, ref max) => {
927                 min.to_gecko_style_coord(gecko_min);
928                 max.to_gecko_style_coord(gecko_max);
929             },
930         }
931     }
932 }
933 
934 impl TrackListValue<LengthOrPercentage, Integer> {
935     /// Return TrackSize from given two nsStyleCoord
from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self936     pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
937         TrackListValue::TrackSize(TrackSize::from_gecko_style_coords(gecko_min, gecko_max))
938     }
939 
940     /// Save TrackSize to given gecko fields.
to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T)941     pub fn to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T) {
942         use values::generics::grid::TrackListValue;
943 
944         match *self {
945             TrackListValue::TrackSize(ref size) => size.to_gecko_style_coords(gecko_min, gecko_max),
946             _ => unreachable!("Should only transform from track-size computed values"),
947         }
948     }
949 }
950 
951 impl<T> Rect<T> where T: GeckoStyleCoordConvertible {
952     /// Convert this generic Rect to given Gecko fields.
to_gecko_rect(&self, sides: &mut ::gecko_bindings::structs::nsStyleSides)953     pub fn to_gecko_rect(&self, sides: &mut ::gecko_bindings::structs::nsStyleSides) {
954         self.0.to_gecko_style_coord(&mut sides.data_at_mut(0));
955         self.1.to_gecko_style_coord(&mut sides.data_at_mut(1));
956         self.2.to_gecko_style_coord(&mut sides.data_at_mut(2));
957         self.3.to_gecko_style_coord(&mut sides.data_at_mut(3));
958     }
959 
960     /// Convert from given Gecko data to generic Rect.
from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides) -> Option<::values::generics::rect::Rect<T>>961     pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides)
962                            -> Option<::values::generics::rect::Rect<T>> {
963         use values::generics::rect::Rect;
964 
965         Some(
966             Rect::new(
967                 T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"),
968                 T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"),
969                 T::from_gecko_style_coord(&sides.data_at(2)).expect("coord[2] cound not convert"),
970                 T::from_gecko_style_coord(&sides.data_at(3)).expect("coord[3] cound not convert")
971             )
972         )
973     }
974 }
975 
976 impl<L> VerticalAlign<L> {
977     /// Converts an enumerated value coming from Gecko to a `VerticalAlign<L>`.
from_gecko_keyword(value: u32) -> Self978     pub fn from_gecko_keyword(value: u32) -> Self {
979         match value {
980             structs::NS_STYLE_VERTICAL_ALIGN_BASELINE => VerticalAlign::Baseline,
981             structs::NS_STYLE_VERTICAL_ALIGN_SUB => VerticalAlign::Sub,
982             structs::NS_STYLE_VERTICAL_ALIGN_SUPER => VerticalAlign::Super,
983             structs::NS_STYLE_VERTICAL_ALIGN_TOP => VerticalAlign::Top,
984             structs::NS_STYLE_VERTICAL_ALIGN_TEXT_TOP => VerticalAlign::TextTop,
985             structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE => VerticalAlign::Middle,
986             structs::NS_STYLE_VERTICAL_ALIGN_BOTTOM => VerticalAlign::Bottom,
987             structs::NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM => VerticalAlign::TextBottom,
988             structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE => {
989                 VerticalAlign::MozMiddleWithBaseline
990             },
991             _ => panic!("unexpected enumerated value for vertical-align"),
992         }
993     }
994 }
995 
996 impl TextAlign {
997     /// Obtain a specified value from a Gecko keyword value
998     ///
999     /// Intended for use with presentation attributes, not style structs
from_gecko_keyword(kw: u32) -> Self1000     pub fn from_gecko_keyword(kw: u32) -> Self {
1001         match kw  {
1002             structs::NS_STYLE_TEXT_ALIGN_LEFT => TextAlign::Left,
1003             structs::NS_STYLE_TEXT_ALIGN_RIGHT => TextAlign::Right,
1004             structs::NS_STYLE_TEXT_ALIGN_CENTER => TextAlign::Center,
1005             structs::NS_STYLE_TEXT_ALIGN_JUSTIFY => TextAlign::Justify,
1006             structs::NS_STYLE_TEXT_ALIGN_MOZ_LEFT => TextAlign::MozLeft,
1007             structs::NS_STYLE_TEXT_ALIGN_MOZ_RIGHT => TextAlign::MozRight,
1008             structs::NS_STYLE_TEXT_ALIGN_MOZ_CENTER => TextAlign::MozCenter,
1009             structs::NS_STYLE_TEXT_ALIGN_CHAR => TextAlign::Char,
1010             structs::NS_STYLE_TEXT_ALIGN_END => TextAlign::End,
1011             _ => panic!("Found unexpected value in style struct for text-align property"),
1012         }
1013     }
1014 }
1015 
1016 /// Convert to String from given chars pointer.
string_from_chars_pointer(p: *const u16) -> String1017 pub unsafe fn string_from_chars_pointer(p: *const u16) -> String {
1018     use std::slice;
1019     let mut length = 0;
1020     let mut iter = p;
1021     while *iter != 0 {
1022         length += 1;
1023         iter = iter.offset(1);
1024     }
1025     let char_vec = slice::from_raw_parts(p, length as usize);
1026     String::from_utf16_lossy(char_vec)
1027 }
1028