@@ -601,7 +601,52 @@ const (
601
601
canDiscardWhitespaceAfter
602
602
)
603
603
604
+ // Note: This function is hot in profiles
604
605
func (p * printer ) printIdent (text string , mode identMode , whitespace trailingWhitespace ) {
606
+ n := len (text )
607
+
608
+ // Special escape behavior for the first character
609
+ initialEscape := escapeNone
610
+ switch mode {
611
+ case identNormal :
612
+ if ! css_lexer .WouldStartIdentifierWithoutEscapes (text ) {
613
+ initialEscape = escapeBackslash
614
+ }
615
+ case identDimensionUnit , identDimensionUnitAfterExponent :
616
+ if ! css_lexer .WouldStartIdentifierWithoutEscapes (text ) {
617
+ initialEscape = escapeBackslash
618
+ } else if n > 0 {
619
+ if c := text [0 ]; c >= '0' && c <= '9' {
620
+ // Unit: "2x"
621
+ initialEscape = escapeHex
622
+ } else if (c == 'e' || c == 'E' ) && mode != identDimensionUnitAfterExponent {
623
+ if n >= 2 && text [1 ] >= '0' && text [1 ] <= '9' {
624
+ // Unit: "e2x"
625
+ initialEscape = escapeHex
626
+ } else if n >= 3 && text [1 ] == '-' && text [2 ] >= '0' && text [2 ] <= '9' {
627
+ // Unit: "e-2x"
628
+ initialEscape = escapeHex
629
+ }
630
+ }
631
+ }
632
+ }
633
+
634
+ // Fast path: the identifier does not need to be escaped. This fast path is
635
+ // important for performance. For example, doing this sped up end-to-end
636
+ // parsing and printing of a large CSS file from 84ms to 66ms (around 25%
637
+ // faster).
638
+ if initialEscape == escapeNone {
639
+ for i := 0 ; i < n ; i ++ {
640
+ if c := text [i ]; c >= 0x80 || ! css_lexer .IsNameContinue (rune (c )) {
641
+ goto slowPath
642
+ }
643
+ }
644
+ p .css = append (p .css , text ... )
645
+ return
646
+ slowPath:
647
+ }
648
+
649
+ // Slow path: the identifier needs to be escaped
605
650
for i , c := range text {
606
651
escape := escapeNone
607
652
@@ -617,36 +662,15 @@ func (p *printer) printIdent(text string, mode identMode, whitespace trailingWhi
617
662
}
618
663
619
664
// Special escape behavior for the first character
620
- if i == 0 {
621
- switch mode {
622
- case identNormal :
623
- if ! css_lexer .WouldStartIdentifierWithoutEscapes (text ) {
624
- escape = escapeBackslash
625
- }
626
-
627
- case identDimensionUnit , identDimensionUnitAfterExponent :
628
- if ! css_lexer .WouldStartIdentifierWithoutEscapes (text ) {
629
- escape = escapeBackslash
630
- } else if c >= '0' && c <= '9' {
631
- // Unit: "2x"
632
- escape = escapeHex
633
- } else if (c == 'e' || c == 'E' ) && mode != identDimensionUnitAfterExponent {
634
- if len (text ) >= 2 && text [1 ] >= '0' && text [1 ] <= '9' {
635
- // Unit: "e2x"
636
- escape = escapeHex
637
- } else if len (text ) >= 3 && text [1 ] == '-' && text [2 ] >= '0' && text [2 ] <= '9' {
638
- // Unit: "e-2x"
639
- escape = escapeHex
640
- }
641
- }
642
- }
665
+ if i == 0 && initialEscape != escapeNone {
666
+ escape = initialEscape
643
667
}
644
668
}
645
669
646
670
// If the last character is a hexadecimal escape, print a space afterwards
647
671
// for the escape sequence to consume. That way we're sure it won't
648
672
// accidentally consume a semantically significant space afterward.
649
- mayNeedWhitespaceAfter := whitespace == mayNeedWhitespaceAfter && escape != escapeNone && i + utf8 .RuneLen (c ) == len ( text )
673
+ mayNeedWhitespaceAfter := whitespace == mayNeedWhitespaceAfter && escape != escapeNone && i + utf8 .RuneLen (c ) == n
650
674
p .printWithEscape (c , escape , text [i :], mayNeedWhitespaceAfter )
651
675
}
652
676
}
0 commit comments