Closed Bug 1229302 Opened 9 years ago Closed 7 years ago

twitter card title and description are truncated in firefox on Linux

Categories

(Web Compatibility :: Site Reports, defect)

Firefox 43
Unspecified
Linux
defect
Not set
normal

Tracking

(platform-rel +)

RESOLVED FIXED
Tracking Status
platform-rel --- +

People

(Reporter: vasvir2, Unassigned, NeedInfo)

References

()

Details

(Whiteboard: [2016-GBT-Y] [js] [css] [sitewait] [platform-rel-Twitter])

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0 Iceweasel/42.0
Build ID: 20151104000845

Steps to reproduce:

In my site I have
<meta name='twitter:title' content='some title of the page'/>
<meta name='twitter:description' content='A biggish description of the page/>

The issue is also reported here https://twittercommunity.com/t/why-are-my-title-and-description-being-truncated/52663/7 for Firefox/Ubuntu


Actual results:

The title and the description is truncated and an ellipsis (...) is added instead.


Expected results:

No truncation should happen. The description and the title should flow following standard html layout.

In Firefox/Windows it is working properly.
OS: Unspecified → Linux
Hello Vassilis,

Could you please give me more in-depth steps on how to reproduce (ie. Website url (I cant tell if you're on twitter.com or using data on your own site from twitter.com), screenshots, etc)?

Thank you,

Justin
Flags: needinfo?(vasvir2)
Sure,

the twitter thread  https://twittercommunity.com/t/why-are-my-title-and-description-being-truncated/52663/7 has descriptions and screenshots posted. Here is one https://discourse-cdn.global.ssl.fastly.net/twitter/uploads/default/optimized/2X/d/d176fae271656d5b1bc3ee437e56eb5f6c5e8f95_1_575x500.png

Here is a twitter account where you can see the problem (no need to log in or anything) https://twitter.com/webecodibergamo/ You just need to find some tweets with a view summary option and click there. If you press F12 and check the truncated elements you can see that it actually the content is there. It justs that firefox decided to truncate it to two characters + ...

Remember that is reproducible on firefox/linux (Iceweasel/Debian for me) but also in firefox/ubuntu.

Hope that helps

Tell me if you need something else and I misunderstood...
Flags: needinfo?(vasvir2)
Nope - scratch that.

The content is not actually there. In the DOM there is actual two letter + ... So it looks like a javascript size evaluation thingy - still a bug though.
I'm going to open a webcompat.com bug to track this. A search for related CSS bugs around text-overflow: ellipsis did not find anything. I'm wondering if this is a twitter.com issue. 

https://webcompat.com/issues/2010
This is not happening on Firefox Macintosh same version as far as I can see.
I wonder if Vassily could test with a clean profile no adds-on, etc.
Flags: needinfo?(vasvir2)
Hi Karl,

As I have noted above the bug does not exist in Firefos/Windows only in Firefox/Linux. It is good to know that MacOSX doesn't have the bug.

Yep it is still doing it with a brand new profile.
Flags: needinfo?(vasvir2)
Since @karlcow and Vassals replicated on Linux I'm going to verify and move this to a component. https://bugzilla.mozilla.org/show_bug.cgi?id=883884 looks like a related bug. Needinfo-ing Ted on this.
Status: UNCONFIRMED → NEW
Component: Untriaged → CSS Parsing and Computation
Ever confirmed: true
Flags: needinfo?(ted.clancy)
Product: Firefox → Core
"a component"?  Why not try for "the right component"?

Given that the DOM doesn't contain the right thing, chances are this is in fact a twitter bug of some sort.  The screenshots from Karl not reproducing aren't looking at the same tweet as the screenshot in comment 2, right?

I'm 99% sure this is either a straight-up bug in Twitter's JS or a matter of slightly different font metrics on different platforms causing that JS to do the wrong thing.  Have you tried to reproduce with different font settings (e.g. overriding page fonts entirely with the default ones, setting a minimum font size, etc)?  Have you tried spoofing the Linux user-agent on Windows/Mac or vice versa?

Over to "General" for now, but I'm betting this ends up as tech evang.
Component: CSS Parsing and Computation → General
Flags: needinfo?(ehumphries)
A small addition because I was intrigued by the font issue.

One more test: Debian Linux version 44.0b2
I switched to View/Zoom/Text Only and made the text really really small. Then I reloaded and the text was shown normally (no ellipsis - unreadable smallish of course).

Hope that helps.
That sure makes it likely that the only reason this is "Linux only" is because of the particular font metrics for the particular fonts used on Linux here...
Appears related to "TeX Gyre Heros" to me. If i override sans-serif with seemingly any other font, it looks correct. "TeX Gyre Heros" is supposed to be a replacement for Helvetica.
Moving to web advocacy then, given last three comments.
Component: General → Desktop
Flags: needinfo?(ehumphries)
Product: Core → Tech Evangelism
Target Milestone: --- → Feb
Version: 42 Branch → Firefox 43
Andrew where the TeX Gyre Heros comes from: 

A. User choices, Linux distribution, 
B. Firefox install 
or 
C. twitter web font. 

I'm not sure it is an evangelism bug at all, if it's related to installed fonts on Linux. Just tell twitter that they could test on Linux.
Flags: needinfo?(irv)
Vassily, 
Does it happen on linux with Chrome or Opera on Blink rendering engine?
Flags: needinfo?(vasvir2)
(In reply to Karl Dubost :karlcow from comment #13)
> Andrew where the TeX Gyre Heros comes from: 
> 
> A. User choices, Linux distribution, 
> B. Firefox install 
> or 
> C. twitter web font. 
> 
> I'm not sure it is an evangelism bug at all, if it's related to installed
> fonts on Linux. Just tell twitter that they could test on Linux.

Instllaed in packed "fonts-texgyre" on debian, not one i recall installing myself, so A.

I don't see how this is twitter's fault to be honest, as far as I can see the CSS is just:

font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;

new install of chromium is choosing to render this using Arial
Flags: needinfo?(irv)
Thanks a lot Andrew.
I would be in favor of closing this as worksforme. Because indeed twitter doesn't necessary know about all the bad fonts out there ^_^
Just to let you know that Chrome on linux also works correctly.

I also confirm that by removing the the texgyre fonts firefox also works correctly.

The question though is why firefox decided to render with these fonts and not with the fonts chrome uses?

Tex Gyre fonts are required by texlive as you can see in apt-cache rdepends below

root@beyonder:~# apt-cache rdepends fonts-texgyre                                                           
fonts-texgyre                                                                                               
Reverse Depends:                                                                                            
  tex-gyre                                                                                                  
  fonts-urw-base35                                                                                          
 |0ad-data-common                                                                                           

root@beyonder:~# apt-cache rdepends fonts-texgyre tex-gyre fonts-urw-base35                                
fonts-texgyre                                                                                               
Reverse Depends:                                                                                            
  tex-gyre                                                                                                  
  fonts-urw-base35                                                                                          
 |0ad-data-common                                                                                           
tex-gyre
Reverse Depends:
  fonts-texgyre
  texlive-full
  texlive-fonts-recommended
  fonts-texgyre
  tex-common
  0ad-data-common
  context
fonts-urw-base35
Reverse Depends:
Flags: needinfo?(vasvir2)
According to debian package /usr/share/doc/tex-gyre/README-TeX-Gyre-Heros.txt

The homepage of the hero font is 
http://www.gust.org.pl/projects/e-foundry/tex-gyre/heros

Maybe somebody should tell them about that bug? Do you think it is something they can fix?


     Vassilis
Karl, there is certainly a bug in twitter's page here, imo: they're creating a brittle UI that doesn't work if the font metrics are just a bit different, no?  It'll break not only for the TeX Gyre Heros font but also for users who override website fonts for accessibility reasons.  Note that I doubt there's an actual "bug" in the TeX Gyre Heros font, at least given the evidence so far...

As for why we're using that font, that's a good question.  Clearly Twitter is doing some manual text measurement _somewhere_ here; it's not obvious whether it's doing that with the font-family settings listed in comment 15.

Just to check, what does :

  fc-match '"Helvetica Neue",Helvetica,Arial,sans-serif'

return on the relevant systems?
In one of my systems which exhibit the bug and on which I don't have deleted the tex-gyre fonts I get:

bill@doddo:~$ fc-match '"Helvetica Neue",Helvetica,Arial,sans-serif'
texgyreheros-regular.otf: "TeX Gyre Heros" "Regular"

Does anybody know
1) Is there a fontconfig option I could use to remedy this without deleting tex-gyre fonts?
2) Why chrome does select Arial instead of Tex-gyre for the twitter page
3) Is it a fact that there is a bug in the font? Anything more concrete on this?
> 1) Is there a fontconfig option I could use to remedy this without deleting tex-gyre fonts?
> 2) Why chrome does select Arial instead of Tex-gyre for the twitter page

Hoping Jonathan knows something about this part.

> 3) Is it a fact that there is a bug in the font?

No.  In fact, as I said in comment 19 I suspect the bug is in twitter's code...  It's _possible_ that the font has some sort of weird font metrics that confuse said code, but it's just as likely that the font metrics are not particularly weird and twitter just unreasonably assumes things about the sizes of glyphs that happen to not be true in this font.
Flags: needinfo?(jfkthame)
(In reply to Boris Zbarsky [:bz] from comment #21)
> > 1) Is there a fontconfig option I could use to remedy this without deleting tex-gyre fonts?

It looks like the fonts-texgyre package installs a couple of files

  /etc/fonts/conf.d/30-fonts-texgyre-aliases.conf
  /etc/fonts/conf.d/30-metric-aliases.conf

that alias the family name "Helvetica" to "TeX Gyre Heros" (among other things); at least that's what it does on my Ubuntu VM. So that's why we end up using TeX Gyre Heros, given a CSS font-family list of '"Helvetica Neue",Helvetica,Arial,sans-serif'; we're obeying the fontconfig configuration.

Deleting those two files causes us to ignore Heros and fall back to Arial (or whatever other sans-serif font is configured, if Arial isn't available).


> > 2) Why chrome does select Arial instead of Tex-gyre for the twitter page

Presumably Chrome does not respect fontconfig aliases, so it just uses the first actual font it finds from the given CSS font-family list.


As for why the problem occurs with TeX Gyre Heros.... I don't know, offhand. Clearly twitter is doing some kind of text measurement and truncation, and it's going wrong; but whether it's purely their code at fault or odd behavior triggered by a bug in the font is hard to say without digging deeper in to what they're actually doing.
Flags: needinfo?(jfkthame)
Ok let's see a bit more
Let's use the same URI than this screenshot.
https://twittercommunity.com/t/why-are-my-title-and-description-being-truncated/52663/3

The post is at https://twitter.com/webecodibergamo/status/646715565399085058

The card is an iframe with the following src
https://twitter.com/i/cards/tfw/v1/646715565399085058?cardname=summary_large_image&earned=true&lang=en#xdm_e=https%3A%2F%2Ftwitter.com&xdm_c=default7238&xdm_p=1


The image and text are wrapped in an `a` element too


```html
<a data-card-breakpoints="w550 w500 w450 w400 w350 w300 w250 w200 w150 w100 w50 " 
   class=" js-openLink u-block TwitterCardsGrid-col--12 TwitterCard-container TwitterCard-container--clickable SummaryCard--large" 
   href="http://t.co/vlwcBgM3dV">

  <div class="SummaryCard-image TwitterCardsGrid-col--12">
    <div class="tcu-imageContainer tcu-imageAspect--2to1">
  <div class="tcu-imageWrapper" 
       style="background-image:url(https://o.twimg.com/2/proxy.jpg?t=HBj_AWh0dHA…);">
    <img class="u-block" src="https://o.twimg.com/2/proxy.jpg?t=HBj_AWh0dHA6…" 
         alt="Photo published for Il Gigante in stato di agitazione Blocco degli straordinari per 60 lavoratori">
  </div>
</div>
  </div>
  <div class="SummaryCard-contentContainer TwitterCardsGrid-col--12">
    <div class="SummaryCard-content">
  
  <h2 class="TwitterCard-title js-cardClick tcu-textEllipse--multiline">Il Gigante in stato di agitazione Blocco degli straordinari per 60 lavoratori</h2>

  <p class="tcu-resetMargin u-block TwitterCardsGrid-col--spacerTop tcu-textEllipse--multiline">Stato di agitazione al Gigante, con la Cgil che annuncia: «Contro la volontà aziendale di stravolgere i contenuti del contratto integrativo (su cui la discussione fra sindac...</p>

  <span class="u-block TwitterCardsGrid-col--spacerTop SummaryCard-destination">ecodibergamo.it</span>

</div>
  </div>
</a>
```

but The issue is happening on the 

```html
<div class="SummaryCard-content">  
  <h2 class="TwitterCard-title js-cardClick tcu-textEllipse--multiline">…</h2>
  <p class="tcu-resetMargin u-block TwitterCardsGrid-col--spacerTop tcu-textEllipse--multiline">…</p>
  <span class="u-block TwitterCardsGrid-col--spacerTop SummaryCard-destination">…</span>
</div>
```

When the URL is loaded individually we can see the ellipsis at work by resizing the window. This is handle by an overflow and a css. The full text to a certain extent. is there in the source code (HTTP Request):

      Stato di agitazione al Gigante, con la Cgil che annuncia: 
      «Contro la volontà aziendale di stravolgere i contenuti 
      del contratto integrativo (su cui la discussione fra 
      sindacati e azienda si è...

So the js doesn't seem to play on the length of the text or the ellipsis. 

```css
.TwitterCard .SummaryCard--large:not([data-card-breakpoints~="w300"]) .SummaryCard-content p {
	max-height: 1.3em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
```

The full


As we can see the CSS class has a value called 
    tcu-textEllipse--multiline
so that sounds like a good start.

In https://ton.twimg.com/tfw/js/native_bundle_v1_7aa0d5ba85b5b41c10ac5f85a429cc536616d2ac.js
We can find 
    CARD_ELLIPSIS: '.tcu-textEllipse--multiline',


This is used only once in the code.

```js
        handleResize: function () {
          var e = document.querySelector(r.selectors.CARD_CONTAINER),
          t = document.querySelector(r.selectors.CARD_CONTAINER + ' ' + r.selectors.CARD_CONTENT_CONTAINER),
          n = e.offsetHeight,
          o = e.offsetWidth;
          r.host && 'function' == typeof r.host.resizeCard && r.host.resizeCard({
            height: n + 'px'
          });
          for (var i = '', u = Math.floor(o / r.RESPONSIVE_STEP_SIZE); u > 0; u--) i += 'w' + u * r.RESPONSIVE_STEP_SIZE + ' ';
          t.setAttribute(r.dataAttrs.CARD_BREAKPOINTS, i),
          a(r.selectors.CARD_ELLIPSIS)
        },
```


The other part is the multiline, because the current is not only overflowing, it's first wrapping in a multiline before doing the ellipsis. I can see also that the script twitter-text-js v1.13.0 is playing **a lot** with CharCode.

But I haven't found yet the culprit.

Let's see if andyhume has an idea
http://twitter.com/MozWebCompat/status/691838006156738565
Flags: needinfo?(andyhume)
Whiteboard: [2016-GBT-Y] → [2016-GBT-Y] [js] [css] [sitewait]
Looking at 
  function multilineEllipses() {… }

I wonder if it's related to our issue, or more exactly the interaction with fonts-texgyre

  function multilineEllipses() {
    this.defaultAttrs({
      unEllipsifiedTextClass: 'js-ellipsis',
      unEllipsifiedTextSelector: '.js-ellipsis',
      maxCharsRemoveEnsureEndOnWordBreak: 5
    }),
    this.after('initialize', function () {
      if (typeof document.createRange == 'undefined') return;
      this.on(document, 'uiSwiftLoaded uiPageChanged uiHasInjectedNewTimeline uiHasInjectedOldTimelineItems uiHasInjectedRangeTimelineItems dataTweetConversationResult uiOverlayUpdate uiTrendsDisplayed uiShowMoreTrends uiCommerceTabToggled', this.addEllipses)
    }),
    this.addEllipses = function () {
      var a = this.select('unEllipsifiedTextSelector').filter(':visible');
      a.removeClass(this.attr.unEllipsifiedTextClass),
      a.each(this.addEllipsis.bind(this))
    },
    this.addEllipsis = function (a, b) {
      var c = $(b),
      d = this.createRange(c);
      if (!d.hasOverflow()) return;
      c.data('full-text', c.text()),
      d.shortenToVisibleContent(),
      d.ensureLastLineAvailableWidth(this.maxEllipsisWidth(c)),
      d.shortenToNearestWordBreak({
        maxCharsToRemove: this.attr.maxCharsRemoveEnsureEndOnWordBreak
      });
      var e = d.toDocumentFragment();
      e.appendChild(document.createTextNode('…')),
      c.html(e),
      this.trigger(c, 'uiEllipsisAdded')
    },
    this.maxEllipsisWidth = function (a) {
      var b = parseInt(a.css('font-size'));
      return b * 2
    },
    this.createRange = function (a) {
      return new MultilineTextRange(a)
    }
  }
Karl,

very good analysis. I haven't noticed the iframe.

certainly looks suspicious with names like shortenToVisibleContent(), shortenToNearestWordBreak(), maxCharsRemoveEnsureEndOnWordBreak

Thanks for the eduntaiment :-)
The code Karl found sure looks like a smoking gun. Surprise! It's not multilineEllipses and friends causing this, it's this nugget:

            for (var t, r = document.querySelectorAll(e), n = 100, o = 0; t = r[o]; o++) {
                var i = t.offsetHeight + 1;
                if (i > 0 && t.scrollHeight > 0)
                    for (var a = t.textContent.split(""), u = 0; n > u && (t.scrollHeight > i && a.length > 3); u++){
                        a.splice(a.length - 3, 3);
                        t.textContent = a.join("") + "...";
                    }
            }

(From https://ton.twimg.com/tfw/js/native_bundle_v1_d0bb9154dccd9fe82abde663c26207e7b58912c1.js - wrapped by me with some extra {})

So this removes up to 300 characters at a time depending on the offsetHeight/scrollHeight figures. (BTW - I see the code being called more than once for the same element - on second run it obviously removes another 300 chars).

Now, apparently something about the texgyre font makes Firefox report scrollHeight as two px larger than offsetHeight - consistently, even when the text fits on one line. When this code runs in Windows it leaves the loop with offsetHeight and scrollHeight both being 18 for the header and 36 for the body text. On Ubuntu with texgyre fonts scrollHeight remains 20 when offsetHeight reaches 18, and 38 when offsetHeight is 36. Don't know how something about the font metrics cause this - but what are our suggestion for Twitter if they want to make this code more robust?
> Don't know how something about the font metrics cause this

Just having somewhat taller ascenders/descenders at the same font size could do this, no?

As far as what to suggest to twitter.... they're checking t.scrollHeight > t.offsetHeight + 1, right?  What is that test _really_ after?  It looks like they want "is overflowing vertically but we fudge it because lots of fonts have descenders or ascenders that overflow the line box" or some such.   But also, it really depends on the styles of the element and its kids.  offsetHeight measures to the border edge, but scrollHeight measures to margin edges of kids...

Anyway, it's hard to suggest something specific without having some idea of what their markup/styles look like around this stuff and what situation they're trying to detect.
Maybe this is obvious to the experts, but it's not just the font that causes this - I have two machines, one of which suffers from this and one which does not, both of which showed "TeX Gyre Heros" as the fc-match output.  Both report 96x96 dpi from xdpyinfo, for what it's worth, but the problematic one has two monitors of different resolution.
Whiteboard: [2016-GBT-Y] [js] [css] [sitewait] → [2016-GBT-Y] [js] [css] [sitewait] [platform-rel-Twitter]
platform-rel: --- → ?
platform-rel: ? → +
I have this issue on my Linux machine with Firefox. The issue does not show up with Chrome.

Making `Nimbus Sans L` an alias for `Helvetica Neue` works around this issue. I do that by putting the following in ~/.fonts.conf:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

  <!-- TeX Gyre messes up Twitter -->
  <alias binding="same">
    <family>Helvetica Neue</family>
    <accept>
      <family>Nimbus Sans L</family>
    </accept>
  </alias>

</fontconfig>
Rank: 5
Contacted through the partner mailing-list.
Jose Antonio notes via our ML (01/2017) that this is being tracked internally. Have pinged for an update, earlier today.
(In reply to Vassilis Virvilis from comment #17)
> Just to let you know that Chrome on linux also works correctly.
> 
> I also confirm that by removing the the texgyre fonts firefox also works
> correctly.
> 
> The question though is why firefox decided to render with these fonts and
> not with the fonts chrome uses?

So twitter will be deploying a fix, because they care about the developer community. That said, they wonder why we do not fix it on our side too.
Flags: needinfo?(bzbarsky)
Fix what on our side?  On our side we're just using the fonts that the system is configured to use, with the metrics those fonts report.  What fix do they expect?
Flags: needinfo?(bzbarsky) → needinfo?(kdubost)
(In reply to Boris Zbarsky [:bz] (still a bit busy) from comment #33)
> On our side we're just using the fonts that the
> system is configured to use, with the metrics those fonts report. 

yup. My understanding too.

I guess it's because on the same computer with Chrome, different fonts are selected it seems (if I understood correctly the comments above). Boris do you know if there's something specific on the side of Firefox that would make it decide to choose a different font than Chrome on the same system.

There is also Comment #28 
Could it be rounding issues? 

(just wondering where we can balance both sides of the issue.)
Flags: needinfo?(kdubost)
> Boris do you know if there's something specific on the side of Firefox that would make it decide to
> choose a different font than Chrome on the same system.

Sure, if they don't respect fontconfig aliases.  See comment 22.  But that's a bug in Chrome.
Thanks Boris. It clarifies. I had missed that.
hmmm re-reading the full thread.
(the twitter issue will be fixed soon. They are deploying a patch for it)
I just want to be sure if we are not missing anything:

Comment 22
Chrome doesn't respect fontconfig alias.
Yes but what is happening in rendering if we force this specific font. Same behavior than Firefox or not?

Comment 28
Using the same "TeX Gyre Heros", one machine exhibits the issue, the one with two monitor of different resolutions. One doesn't.


I tried to install Tex Gyre on macos but could not reproduce the issue.
> Yes but what is happening in rendering if we force this specific font.

I'm not sure anyone has tested that.
> Yes but what is happening in rendering if we force this specific font. Same
> behavior than Firefox or not?

I've created an example that reproduces the bug on my machine (Debian Sid with Firefox Nightly 54.0a1 (2017-02-22) 64-bit) with Twitter's code and minimal styles: http://jsbin.com/kitawin/7/edit?html,css,js,output
Expected behavior: on click the header's text should be shortened to fit the Output tab width in one line.

In Firefox, it is shortened up to the first two characters for both `font-family: "TeX Gyre Heros";` and `font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;`.

In Chrome (v.58.0.03018.3 dev 64-bit), it works correctly for the second case (effective font is 'Liberation Sans') but works the same way as Firefox when forced to use 'TeX Gyre Heros'.
The ellipsis() function there is somewhat fragile and font-dependent. It will fail (as we're seeing here) if the font that ends up being used for the header has a relatively large ascent+descent, such that the scrollHeight of a single line of text is greater than 1.3em, because it uses that (rather arbitrary) criterion to try and determine whether the text has wrapped.

(For an extreme example, try setting the font to Zapfino on Mac OS.)

IIRC, the TeX Gyre fonts tend to have relatively generous ascent/descent metrics, maybe because they support lots of accents etc., so it's not surprising they could encounter this. The exact behavior may vary across platforms (even for the same font) due to platform differences in how font metrics are handled (hinting, rounding, etc).

Increasing the max-height value in the "card .h2" style properties will help (i.e. make it less likely the problem will occur); setting it to something like 1.8em would probably be OK for almost all "normal" fonts (although Zapfino would still fail).

A more robust approach would be for the ellipsis() function to initially truncate the text to a single character, get *that* scrollHeight, and then use (say) 1.5x that as the target for the main truncation loop.
It looks like Twitter deployed a new version of ellipsis() function: now, instead of
  var i = t.offsetHeight + 1;
it does
  var i = t.offsetHeight + 3;
:)

This fixes the issue for me.
perfect. Thanks for checking.
And thanks to Twitter.
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Product: Tech Evangelism → Web Compatibility
You need to log in before you can comment on or make changes to this bug.