LCOV - code coverage report
Current view: directory - gfx/thebes - gfxFT2Utils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 162 0 0.0 %
Date: 2012-06-02 Functions: 8 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Foundation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Vladimir Vukicevic <vladimir@mozilla.com>
      23                 :  *   Masayuki Nakano <masayuki@d-toybox.com>
      24                 :  *   Behdad Esfahbod <behdad@gnome.org>
      25                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      26                 :  *   Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
      27                 :  *   Takuro Ashie <ashie@clear-code.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      31                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : #include "gfxFT2FontBase.h"
      44                 : #include "gfxFT2Utils.h"
      45                 : #include FT_TRUETYPE_TAGS_H
      46                 : #include FT_TRUETYPE_TABLES_H
      47                 : 
      48                 : #ifdef HAVE_FONTCONFIG_FCFREETYPE_H
      49                 : #include <fontconfig/fcfreetype.h>
      50                 : #endif
      51                 : 
      52                 : #include "prlink.h"
      53                 : 
      54                 : // aScale is intended for a 16.16 x/y_scale of an FT_Size_Metrics
      55                 : static inline FT_Long
      56               0 : ScaleRoundDesignUnits(FT_Short aDesignMetric, FT_Fixed aScale)
      57                 : {
      58               0 :     FT_Long fixed26dot6 = FT_MulFix(aDesignMetric, aScale);
      59               0 :     return ROUND_26_6_TO_INT(fixed26dot6);
      60                 : }
      61                 : 
      62                 : // Snap a line to pixels while keeping the center and size of the line as
      63                 : // close to the original position as possible.
      64                 : //
      65                 : // Pango does similar snapping for underline and strikethrough when fonts are
      66                 : // hinted, but nsCSSRendering::GetTextDecorationRectInternal always snaps the
      67                 : // top and size of lines.  Optimizing the distance between the line and
      68                 : // baseline is probably good for the gap between text and underline, but
      69                 : // optimizing the center of the line is better for positioning strikethough.
      70                 : static void
      71               0 : SnapLineToPixels(gfxFloat& aOffset, gfxFloat& aSize)
      72                 : {
      73               0 :     gfxFloat snappedSize = NS_MAX(floor(aSize + 0.5), 1.0);
      74                 :     // Correct offset for change in size
      75               0 :     gfxFloat offset = aOffset - 0.5 * (aSize - snappedSize);
      76                 :     // Snap offset
      77               0 :     aOffset = floor(offset + 0.5);
      78               0 :     aSize = snappedSize;
      79               0 : }
      80                 : 
      81                 : void
      82               0 : gfxFT2LockedFace::GetMetrics(gfxFont::Metrics* aMetrics,
      83                 :                              PRUint32* aSpaceGlyph)
      84                 : {
      85               0 :     NS_PRECONDITION(aMetrics != NULL, "aMetrics must not be NULL");
      86               0 :     NS_PRECONDITION(aSpaceGlyph != NULL, "aSpaceGlyph must not be NULL");
      87                 : 
      88               0 :     if (NS_UNLIKELY(!mFace)) {
      89                 :         // No face.  This unfortunate situation might happen if the font
      90                 :         // file is (re)moved at the wrong time.
      91               0 :         aMetrics->emHeight = mGfxFont->GetStyle()->size;
      92               0 :         aMetrics->emAscent = 0.8 * aMetrics->emHeight;
      93               0 :         aMetrics->emDescent = 0.2 * aMetrics->emHeight;
      94               0 :         aMetrics->maxAscent = aMetrics->emAscent;
      95               0 :         aMetrics->maxDescent = aMetrics->maxDescent;
      96               0 :         aMetrics->maxHeight = aMetrics->emHeight;
      97               0 :         aMetrics->internalLeading = 0.0;
      98               0 :         aMetrics->externalLeading = 0.2 * aMetrics->emHeight;
      99               0 :         aSpaceGlyph = 0;
     100               0 :         aMetrics->spaceWidth = 0.5 * aMetrics->emHeight;
     101               0 :         aMetrics->maxAdvance = aMetrics->spaceWidth;
     102               0 :         aMetrics->aveCharWidth = aMetrics->spaceWidth;
     103               0 :         aMetrics->zeroOrAveCharWidth = aMetrics->spaceWidth;
     104               0 :         aMetrics->xHeight = 0.5 * aMetrics->emHeight;
     105               0 :         aMetrics->underlineSize = aMetrics->emHeight / 14.0;
     106               0 :         aMetrics->underlineOffset = -aMetrics->underlineSize;
     107               0 :         aMetrics->strikeoutOffset = 0.25 * aMetrics->emHeight;
     108               0 :         aMetrics->strikeoutSize = aMetrics->underlineSize;
     109               0 :         aMetrics->superscriptOffset = aMetrics->xHeight;
     110               0 :         aMetrics->subscriptOffset = aMetrics->xHeight;
     111                 : 
     112               0 :         return;
     113                 :     }
     114                 : 
     115               0 :     const FT_Size_Metrics& ftMetrics = mFace->size->metrics;
     116                 : 
     117                 :     gfxFloat emHeight;
     118                 :     // Scale for vertical design metric conversion: pixels per design unit.
     119                 :     gfxFloat yScale;
     120               0 :     if (FT_IS_SCALABLE(mFace)) {
     121                 :         // Prefer FT_Size_Metrics::x_scale to x_ppem as x_ppem does not
     122                 :         // have subpixel accuracy.
     123                 :         //
     124                 :         // FT_Size_Metrics::y_scale is in 16.16 fixed point format.  Its
     125                 :         // (fractional) value is a factor that converts vertical metrics from
     126                 :         // design units to units of 1/64 pixels, so that the result may be
     127                 :         // interpreted as pixels in 26.6 fixed point format.
     128               0 :         yScale = FLOAT_FROM_26_6(FLOAT_FROM_16_16(ftMetrics.y_scale));
     129               0 :         emHeight = mFace->units_per_EM * yScale;
     130                 :     } else { // Not scalable.
     131                 :         // FT_Size_Metrics doc says x_scale is "only relevant for scalable
     132                 :         // font formats".
     133               0 :         gfxFloat emUnit = mFace->units_per_EM;
     134               0 :         emHeight = ftMetrics.y_ppem;
     135               0 :         yScale = emHeight / emUnit;
     136                 :     }
     137                 : 
     138                 :     TT_OS2 *os2 =
     139               0 :         static_cast<TT_OS2*>(FT_Get_Sfnt_Table(mFace, ft_sfnt_os2));
     140                 : 
     141               0 :     aMetrics->maxAscent = FLOAT_FROM_26_6(ftMetrics.ascender);
     142               0 :     aMetrics->maxDescent = -FLOAT_FROM_26_6(ftMetrics.descender);
     143               0 :     aMetrics->maxAdvance = FLOAT_FROM_26_6(ftMetrics.max_advance);
     144                 : 
     145                 :     gfxFloat lineHeight;
     146               0 :     if (os2 && os2->sTypoAscender) {
     147               0 :         aMetrics->emAscent = os2->sTypoAscender * yScale;
     148               0 :         aMetrics->emDescent = -os2->sTypoDescender * yScale;
     149                 :         FT_Short typoHeight =
     150               0 :             os2->sTypoAscender - os2->sTypoDescender + os2->sTypoLineGap;
     151               0 :         lineHeight = typoHeight * yScale;
     152                 : 
     153                 :         // maxAscent/maxDescent get used for frame heights, and some fonts
     154                 :         // don't have the HHEA table ascent/descent set (bug 279032).
     155               0 :         if (aMetrics->emAscent > aMetrics->maxAscent)
     156               0 :             aMetrics->maxAscent = aMetrics->emAscent;
     157               0 :         if (aMetrics->emDescent > aMetrics->maxDescent)
     158               0 :             aMetrics->maxDescent = aMetrics->emDescent;
     159                 :     } else {
     160               0 :         aMetrics->emAscent = aMetrics->maxAscent;
     161               0 :         aMetrics->emDescent = aMetrics->maxDescent;
     162               0 :         lineHeight = FLOAT_FROM_26_6(ftMetrics.height);
     163                 :     }
     164                 : 
     165                 :     cairo_text_extents_t extents;
     166               0 :     *aSpaceGlyph = GetCharExtents(' ', &extents);
     167               0 :     if (*aSpaceGlyph) {
     168               0 :         aMetrics->spaceWidth = extents.x_advance;
     169                 :     } else {
     170               0 :         aMetrics->spaceWidth = aMetrics->maxAdvance; // guess
     171                 :     }
     172                 : 
     173               0 :     aMetrics->zeroOrAveCharWidth = 0.0;
     174               0 :     if (GetCharExtents('0', &extents)) {
     175               0 :         aMetrics->zeroOrAveCharWidth = extents.x_advance;
     176                 :     }
     177                 : 
     178                 :     // Prefering a measured x over sxHeight because sxHeight doesn't consider
     179                 :     // hinting, but maybe the x extents are not quite right in some fancy
     180                 :     // script fonts.  CSS 2.1 suggests possibly using the height of an "o",
     181                 :     // which would have a more consistent glyph across fonts.
     182               0 :     if (GetCharExtents('x', &extents) && extents.y_bearing < 0.0) {
     183               0 :         aMetrics->xHeight = -extents.y_bearing;
     184               0 :         aMetrics->aveCharWidth = extents.x_advance;
     185                 :     } else {
     186               0 :         if (os2 && os2->sxHeight) {
     187               0 :             aMetrics->xHeight = os2->sxHeight * yScale;
     188                 :         } else {
     189                 :             // CSS 2.1, section 4.3.2 Lengths: "In the cases where it is
     190                 :             // impossible or impractical to determine the x-height, a value of
     191                 :             // 0.5em should be used."
     192               0 :             aMetrics->xHeight = 0.5 * emHeight;
     193                 :         }
     194               0 :         aMetrics->aveCharWidth = 0.0; // updated below
     195                 :     }
     196                 :     // aveCharWidth is used for the width of text input elements so be
     197                 :     // liberal rather than conservative in the estimate.
     198               0 :     if (os2 && os2->xAvgCharWidth) {
     199                 :         // Round to pixels as this is compared with maxAdvance to guess
     200                 :         // whether this is a fixed width font.
     201                 :         gfxFloat avgCharWidth =
     202               0 :             ScaleRoundDesignUnits(os2->xAvgCharWidth, ftMetrics.x_scale);
     203                 :         aMetrics->aveCharWidth =
     204               0 :             NS_MAX(aMetrics->aveCharWidth, avgCharWidth);
     205                 :     }
     206                 :     aMetrics->aveCharWidth =
     207               0 :         NS_MAX(aMetrics->aveCharWidth, aMetrics->zeroOrAveCharWidth);
     208               0 :     if (aMetrics->aveCharWidth == 0.0) {
     209               0 :         aMetrics->aveCharWidth = aMetrics->spaceWidth;
     210                 :     }
     211               0 :     if (aMetrics->zeroOrAveCharWidth == 0.0) {
     212               0 :         aMetrics->zeroOrAveCharWidth = aMetrics->aveCharWidth;
     213                 :     }
     214                 :     // Apparently hinting can mean that max_advance is not always accurate.
     215                 :     aMetrics->maxAdvance =
     216               0 :         NS_MAX(aMetrics->maxAdvance, aMetrics->aveCharWidth);
     217                 : 
     218                 :     // gfxFont::Metrics::underlineOffset is the position of the top of the
     219                 :     // underline.
     220                 :     //
     221                 :     // FT_FaceRec documentation describes underline_position as "the
     222                 :     // center of the underlining stem".  This was the original definition
     223                 :     // of the PostScript metric, but in the PostScript table of OpenType
     224                 :     // fonts the metric is "the top of the underline"
     225                 :     // (http://www.microsoft.com/typography/otspec/post.htm), and FreeType
     226                 :     // (up to version 2.3.7) doesn't make any adjustment.
     227                 :     //
     228                 :     // Therefore get the underline position directly from the table
     229                 :     // ourselves when this table exists.  Use FreeType's metrics for
     230                 :     // other (including older PostScript) fonts.
     231               0 :     if (mFace->underline_position && mFace->underline_thickness) {
     232               0 :         aMetrics->underlineSize = mFace->underline_thickness * yScale;
     233                 :         TT_Postscript *post = static_cast<TT_Postscript*>
     234               0 :             (FT_Get_Sfnt_Table(mFace, ft_sfnt_post));
     235               0 :         if (post && post->underlinePosition) {
     236               0 :             aMetrics->underlineOffset = post->underlinePosition * yScale;
     237                 :         } else {
     238                 :             aMetrics->underlineOffset = mFace->underline_position * yScale
     239               0 :                 + 0.5 * aMetrics->underlineSize;
     240               0 :         }
     241                 :     } else { // No underline info.
     242                 :         // Imitate Pango.
     243               0 :         aMetrics->underlineSize = emHeight / 14.0;
     244               0 :         aMetrics->underlineOffset = -aMetrics->underlineSize;
     245                 :     }
     246                 : 
     247               0 :     if (os2 && os2->yStrikeoutSize && os2->yStrikeoutPosition) {
     248               0 :         aMetrics->strikeoutSize = os2->yStrikeoutSize * yScale;
     249               0 :         aMetrics->strikeoutOffset = os2->yStrikeoutPosition * yScale;
     250                 :     } else { // No strikeout info.
     251               0 :         aMetrics->strikeoutSize = aMetrics->underlineSize;
     252                 :         // Use OpenType spec's suggested position for Roman font.
     253                 :         aMetrics->strikeoutOffset = emHeight * 409.0 / 2048.0
     254               0 :             + 0.5 * aMetrics->strikeoutSize;
     255                 :     }
     256               0 :     SnapLineToPixels(aMetrics->strikeoutOffset, aMetrics->strikeoutSize);
     257                 : 
     258               0 :     if (os2 && os2->ySuperscriptYOffset) {
     259                 :         gfxFloat val = ScaleRoundDesignUnits(os2->ySuperscriptYOffset,
     260               0 :                                              ftMetrics.y_scale);
     261               0 :         aMetrics->superscriptOffset = NS_MAX(1.0, val);
     262                 :     } else {
     263               0 :         aMetrics->superscriptOffset = aMetrics->xHeight;
     264                 :     }
     265                 :     
     266               0 :     if (os2 && os2->ySubscriptYOffset) {
     267                 :         gfxFloat val = ScaleRoundDesignUnits(os2->ySubscriptYOffset,
     268               0 :                                              ftMetrics.y_scale);
     269                 :         // some fonts have the incorrect sign. 
     270               0 :         val = fabs(val);
     271               0 :         aMetrics->subscriptOffset = NS_MAX(1.0, val);
     272                 :     } else {
     273               0 :         aMetrics->subscriptOffset = aMetrics->xHeight;
     274                 :     }
     275                 : 
     276               0 :     aMetrics->maxHeight = aMetrics->maxAscent + aMetrics->maxDescent;
     277                 : 
     278                 :     // Make the line height an integer number of pixels so that lines will be
     279                 :     // equally spaced (rather than just being snapped to pixels, some up and
     280                 :     // some down).  Layout calculates line height from the emHeight +
     281                 :     // internalLeading + externalLeading, but first each of these is rounded
     282                 :     // to layout units.  To ensure that the result is an integer number of
     283                 :     // pixels, round each of the components to pixels.
     284               0 :     aMetrics->emHeight = floor(emHeight + 0.5);
     285                 : 
     286                 :     // maxHeight will normally be an integer, but round anyway in case
     287                 :     // FreeType is configured differently.
     288                 :     aMetrics->internalLeading =
     289               0 :         floor(aMetrics->maxHeight - aMetrics->emHeight + 0.5);
     290                 : 
     291                 :     // Text input boxes currently don't work well with lineHeight
     292                 :     // significantly less than maxHeight (with Verdana, for example).
     293               0 :     lineHeight = floor(NS_MAX(lineHeight, aMetrics->maxHeight) + 0.5);
     294                 :     aMetrics->externalLeading =
     295               0 :         lineHeight - aMetrics->internalLeading - aMetrics->emHeight;
     296                 : 
     297                 :     // Ensure emAscent + emDescent == emHeight
     298               0 :     gfxFloat sum = aMetrics->emAscent + aMetrics->emDescent;
     299                 :     aMetrics->emAscent = sum > 0.0 ?
     300               0 :         aMetrics->emAscent * aMetrics->emHeight / sum : 0.0;
     301               0 :     aMetrics->emDescent = aMetrics->emHeight - aMetrics->emAscent;
     302                 : }
     303                 : 
     304                 : PRUint32
     305               0 : gfxFT2LockedFace::GetGlyph(PRUint32 aCharCode)
     306                 : {
     307               0 :     if (NS_UNLIKELY(!mFace))
     308               0 :         return 0;
     309                 : 
     310                 : #ifdef HAVE_FONTCONFIG_FCFREETYPE_H
     311                 :     // FcFreeTypeCharIndex will search starting from the most recently
     312                 :     // selected charmap.  This can cause non-determistic behavior when more
     313                 :     // than one charmap supports a character but with different glyphs, as
     314                 :     // with older versions of MS Gothic, for example.  Always prefer a Unicode
     315                 :     // charmap, if there is one.  (FcFreeTypeCharIndex usually does the
     316                 :     // appropriate Unicode conversion, but some fonts have non-Roman glyphs
     317                 :     // for FT_ENCODING_APPLE_ROMAN characters.)
     318               0 :     if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
     319               0 :         FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
     320                 :     }
     321                 : 
     322               0 :     return FcFreeTypeCharIndex(mFace, aCharCode);
     323                 : #else
     324                 :     return FT_Get_Char_Index(mFace, aCharCode);
     325                 : #endif
     326                 : }
     327                 : 
     328                 : typedef FT_UInt (*GetCharVariantFunction)(FT_Face  face,
     329                 :                                           FT_ULong charcode,
     330                 :                                           FT_ULong variantSelector);
     331                 : 
     332                 : PRUint32
     333               0 : gfxFT2LockedFace::GetUVSGlyph(PRUint32 aCharCode, PRUint32 aVariantSelector)
     334                 : {
     335               0 :     NS_PRECONDITION(aVariantSelector, "aVariantSelector should not be NULL");
     336                 : 
     337               0 :     if (NS_UNLIKELY(!mFace))
     338               0 :         return 0;
     339                 : 
     340                 :     // This function is available from FreeType 2.3.6 (June 2008).
     341               0 :     static CharVariantFunction sGetCharVariantPtr = FindCharVariantFunction();
     342               0 :     if (!sGetCharVariantPtr)
     343               0 :         return 0;
     344                 : 
     345                 : #ifdef HAVE_FONTCONFIG_FCFREETYPE_H
     346                 :     // FcFreeTypeCharIndex may have changed the selected charmap.
     347                 :     // FT_Face_GetCharVariantIndex needs a unicode charmap.
     348               0 :     if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
     349               0 :         FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
     350                 :     }
     351                 : #endif
     352                 : 
     353               0 :     return (*sGetCharVariantPtr)(mFace, aCharCode, aVariantSelector);
     354                 : }
     355                 : 
     356                 : bool
     357               0 : gfxFT2LockedFace::GetFontTable(PRUint32 aTag, FallibleTArray<PRUint8>& aBuffer)
     358                 : {
     359               0 :     if (!mFace || !FT_IS_SFNT(mFace))
     360               0 :         return false;
     361                 : 
     362               0 :     FT_ULong length = 0;
     363                 :     // TRUETYPE_TAG is defined equivalent to FT_MAKE_TAG
     364               0 :     FT_Error error = FT_Load_Sfnt_Table(mFace, aTag, 0, NULL, &length);
     365               0 :     if (error != 0)
     366               0 :         return false;
     367                 : 
     368               0 :     if (NS_UNLIKELY(length > static_cast<FallibleTArray<PRUint8>::size_type>(-1))
     369               0 :         || NS_UNLIKELY(!aBuffer.SetLength(length)))
     370               0 :         return false;
     371                 :         
     372               0 :     error = FT_Load_Sfnt_Table(mFace, aTag, 0, aBuffer.Elements(), &length);
     373               0 :     if (NS_UNLIKELY(error != 0)) {
     374               0 :         aBuffer.Clear();
     375               0 :         return false;
     376                 :     }
     377                 : 
     378               0 :     return true;
     379                 : }
     380                 : 
     381                 : PRUint32
     382               0 : gfxFT2LockedFace::GetCharExtents(char aChar, cairo_text_extents_t* aExtents)
     383                 : {
     384               0 :     NS_PRECONDITION(aExtents != NULL, "aExtents must not be NULL");
     385                 : 
     386               0 :     if (!mFace)
     387               0 :         return 0;
     388                 : 
     389               0 :     FT_UInt gid = mGfxFont->GetGlyph(aChar);
     390               0 :     if (gid) {
     391               0 :         mGfxFont->GetGlyphExtents(gid, aExtents);
     392                 :     }
     393                 : 
     394               0 :     return gid;
     395                 : }
     396                 : 
     397                 : gfxFT2LockedFace::CharVariantFunction
     398               0 : gfxFT2LockedFace::FindCharVariantFunction()
     399                 : {
     400                 :     // This function is available from FreeType 2.3.6 (June 2008).
     401               0 :     PRLibrary *lib = nsnull;
     402                 :     CharVariantFunction function =
     403                 :         reinterpret_cast<CharVariantFunction>
     404               0 :         (PR_FindFunctionSymbolAndLibrary("FT_Face_GetCharVariantIndex", &lib));
     405               0 :     if (!lib) {
     406               0 :         return nsnull;
     407                 :     }
     408                 : 
     409                 :     FT_Int major;
     410                 :     FT_Int minor;
     411                 :     FT_Int patch;
     412               0 :     FT_Library_Version(mFace->glyph->library, &major, &minor, &patch);
     413                 : 
     414                 :     // Versions 2.4.0 to 2.4.3 crash if configured with
     415                 :     // FT_CONFIG_OPTION_OLD_INTERNALS.  Presence of the symbol FT_Alloc
     416                 :     // indicates FT_CONFIG_OPTION_OLD_INTERNALS.
     417               0 :     if (major == 2 && minor == 4 && patch < 4 &&
     418               0 :         PR_FindFunctionSymbol(lib, "FT_Alloc")) {
     419               0 :         function = nsnull;
     420                 :     }
     421                 : 
     422                 :     // Decrement the reference count incremented in
     423                 :     // PR_FindFunctionSymbolAndLibrary.
     424               0 :     PR_UnloadLibrary(lib);
     425                 : 
     426               0 :     return function;
     427                 : }

Generated by: LCOV version 1.7