Xiaoxiangquan has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/153375

Change subject: Detect tofu with the specified font family, and display popup 
when click the tofu
......................................................................

Detect tofu with the specified font family, and display popup when click the 
tofu

Change-Id: I6f7461a34133e7350a7585bd2a955a7be1b06adc
---
M Resources.php
A resources/css/ext.uls.webfonts.tofu.css
M resources/js/ext.uls.webfonts.js
A resources/js/ext.uls.webfonts.tofu.js
4 files changed, 239 insertions(+), 1 deletion(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UniversalLanguageSelector 
refs/changes/75/153375/1

diff --git a/Resources.php b/Resources.php
index d0a2b79..3220fae 100644
--- a/Resources.php
+++ b/Resources.php
@@ -158,11 +158,20 @@
        ),
 ) + $resourcePaths;
 
+$wgResourceModules['ext.uls.webfonts.tofu'] = array(
+       'scripts' => 'resources/js/ext.uls.webfonts.tofu.js',
+       'styles' => 'resources/css/ext.uls.webfonts.tofu.css',
+       'dependencies' => array(
+               'ext.uls.init',
+       ),
+) + $resourcePaths;
+
 $wgResourceModules['ext.uls.webfonts'] = array(
        'scripts' => 'resources/js/ext.uls.webfonts.js',
        'dependencies' => array(
                'ext.uls.init',
                'ext.uls.preferences',
+               'ext.uls.webfonts.tofu',
        ),
 ) + $resourcePaths;
 
diff --git a/resources/css/ext.uls.webfonts.tofu.css 
b/resources/css/ext.uls.webfonts.tofu.css
new file mode 100644
index 0000000..99f3b9d
--- /dev/null
+++ b/resources/css/ext.uls.webfonts.tofu.css
@@ -0,0 +1,37 @@
+.tofu_popup {
+       width: 300px;
+       display: block;
+       padding: 1px;
+       position: absolute;
+       border: 1px solid #4c77aa;
+       background: #f2f7fd;
+       z-index: 11;
+       zoom: 1;
+       text-align: left;
+}
+
+.tofu_popup h3 {
+       background: #4c77aa;
+       color: #fff;
+       font-size: 20px;
+       padding: 5px;
+       margin: 0px;
+}
+
+.tofu_popup_content {
+       font-size: 15px;
+       line-height: 20px;
+       float: left;
+       width: 100%;
+       height: 100%;
+}
+
+.tofu_popup_bg {
+       position: absolute;
+       display: block;
+       left: 0;
+       top: 0;
+       background: #000;
+       opacity: 0.3;
+       z-index: 10
+}
diff --git a/resources/js/ext.uls.webfonts.js b/resources/js/ext.uls.webfonts.js
index 9bc30ca..8497dc8 100644
--- a/resources/js/ext.uls.webfonts.js
+++ b/resources/js/ext.uls.webfonts.js
@@ -101,7 +101,7 @@
                        width[index] = $fixture.width() || width[index-1];
                        height[index] = $fixture.height();
 
-                       if( index > 0 &&
+                       if ( index > 0 &&
                                ( width[index] !== width[index - 1] ||
                                        height[index] !== height[index - 1] )
                        ) {
@@ -220,6 +220,11 @@
                        // will be applied automatically to such future 
elements.
                        $( 'body' ).data( 'webfonts' ).load( 'Autonym' );
                }, 0 );
+
+               // run later, to wait for all webfonts downloaded and all chars 
rendered
+               setTimeout( function() {
+                       mw.webfonts.markTofus();
+               }, 3000 );
        };
 
        $( document ).ready( function () {
diff --git a/resources/js/ext.uls.webfonts.tofu.js 
b/resources/js/ext.uls.webfonts.tofu.js
new file mode 100644
index 0000000..f36c235
--- /dev/null
+++ b/resources/js/ext.uls.webfonts.tofu.js
@@ -0,0 +1,187 @@
+/**
+ * ULS-Webfonts tofu detection and glyph collector binder
+ *
+ * Copyright (C) 2012 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon 
Harris,
+ * Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland and other
+ * contributors. See CREDITS for a list.
+ *
+ * UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
+ * have to do anything special to choose one license or the other and you don't
+ * have to notify anyone which license you are using. You are free to use
+ * UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @file
+ * @ingroup Extensions
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+( function ( $, mw ) {
+       'use strict';
+
+       var tofuSalt = '\u0D00',
+               // cache for tofu images: { fontFamily => tofuImage }
+               tofuImages = {},
+               // cache for tofu detection: { fontFamily => { char => 
isTofuOrNot } }
+               tofuMaps = {};
+
+       mw.webfonts = mw.webfonts || {};
+       /**
+        * Convert a single grapheme to image pixel array
+        *
+        * Draw the character on canvas, and return the image in format: rgba 
...
+        * Note that some unicode code units do not form a single, complete 
grapheme
+        * (e.g. a surrogate such as \uD800 or a combining character such as 
\u0302).
+        * In other cases, the number of graphemes depends on the font (e.g. 
Malayalam)
+        *
+        * @param {string} grapheme A string that forms a single grapheme (e.g. 
a single Han character)
+        * @return {array}
+        */
+       function charToImage( ch, fontFamily ) {
+               var $canvas, canvasContext;
+
+               // width/height=1+12+1, put the 12px char at center, and leave 
1px as
+               // padding. 12px * 12px is large enough to render a Han 
character. Some
+               // complex scripts may have wider graphemes formed of many 
codepoints,
+               // but then they probably don't also have fixed-width rendering.
+               $canvas = $( '<canvas>' )
+                       .prop( {
+                               width: 14,
+                               height: 14
+                       } );
+
+               canvasContext = $canvas[0].getContext( '2d' );
+               canvasContext.font = '12px ' + fontFamily;
+               canvasContext.fillText( ch, 1, 11 );
+
+               return canvasContext
+                       .getImageData( 0, 0, $canvas[0].width, 
$canvas[0].height )
+                       .data;
+       }
+
+       /**
+        * Detect tofu by comparing image pixels
+        *
+        * Create tofu's and every character's images, compare them to see if 
any
+        * character is rendered as a tofu.
+        * 
+        * TODO: in some non-Han unicode ranges, multiple code
+        * points form a single grapheme (e.g. combining accents, Indian 
scripts).
+        * In some cases, the number of graphemes even depends on the font 
(e.g. Malayalam).
+        *
+        * @param {string} text Text to detect
+        * @param {string} fontFamily The fontFamily setting
+        * @return {array} Tofus detected in text with the fontFamily setting
+        */
+       function detectTofuByImage( text, fontFamily ) {
+               var charImage, diff, i, j, ch, tofuMap, tofuImage, tofus = [];
+
+               // init and get the tofu map
+               if ( !tofuMaps.hasOwnProperty( fontFamily ) ) {
+                       tofuMaps[ fontFamily ] = {};
+               }
+               tofuMap = tofuMaps[ fontFamily ];
+
+               for ( i in text ) {
+                       ch = text[i];
+                       // skip spaces
+                       if ( /\s/.test( ch ) ) {
+                               continue;
+                       }
+                       // cache hitted
+                       if ( tofuMap.hasOwnProperty( ch ) ) {
+                               if ( tofuMap[ ch ] ) {
+                                       tofus.push( ch );
+                               }
+                               continue;
+                       }
+
+                       // init and get the tofu image
+                       if ( !tofuImages.hasOwnProperty( fontFamily ) ) {
+                               tofuImages[ fontFamily ] = charToImage( 
tofuSalt, fontFamily ); // a known tofu
+                       }
+                       tofuImage = tofuImages[ fontFamily ];
+
+                       // detect by comparing image
+                       charImage = charToImage( ch, fontFamily );
+                       tofuMap[ ch ] = true;
+                       for ( j = 0; j < tofuImage.length; j++ ) {
+                               if ( charImage[j] !== tofuImage[j] ) {
+                                       // different from the tofu image, it's 
not a tofu
+                                       tofuMap[ ch ] = false;
+                                       break;
+                               }
+                       }
+
+                       // No difference has been found, tofu detected
+                       if ( tofuMap[ ch ] ) {
+                               tofus.push( ch );
+                       }
+               }
+               return tofus;
+       }
+
+       mw.webfonts.showTofuPopup = function( charCode, fontFamily ) {
+               var hexCharCode = '0x' + charCode.toString(16).toUpperCase(),
+                       tofuPopupHtml =
+                       '<h3>Missing Glyph</h3>'
+                       + '<table class="popup_content">'
+                       + '<tr><td>Glyph\'s Unicode </td><td>: ' + hexCharCode 
+ '</td></tr>'
+                       + '<tr><td>Font Family </td><td>: ' + fontFamily + 
'</td></tr>'
+                       + '</table>';
+
+               // popup background
+               $( '<div>' )
+                       .prop( {
+                               'id': 'tofuPopupBg',
+                               'class': 'tofu_popup_bg'
+                       } )
+                       .css( {
+                               'width': $( window ).width() + "px",
+                               'height': Math.max( $( window ).height(), $( 
document ).height() ) + "px"
+                       } )
+                       .click( function() {
+                               $( '.tofu_popup' ).remove();
+                               $( this ).remove();
+                       } )
+                       .appendTo( $( 'body' ) );
+
+               // popup window
+               $( '<div>' )
+                       .prop( { 'class': 'tofu_popup' } )
+                       .html( tofuPopupHtml )
+                       .css( {
+                               'left': ( $( window ).width() - 302 ) / 2 + 
"px",
+                               'top': ( $( window ).height() - 302 ) / 2 + "px"
+                       } )
+                       .appendTo( $( 'body' ) );
+       };
+
+       /**
+        * Search tofus in the DOM tree, and mark it with a link to a popup 
window
+        */
+       mw.webfonts.markTofus = function() {
+               var fontFamily, text, tofus, i, $tofuPopup, callback;
+
+               $('#content * :not(:empty)').each( function() {
+                       // only process leaves in the tree
+                       if ( $(this).children().length > 0 ) {
+                               return;
+                       }
+                       fontFamily = $(this).css('fontFamily');
+                       text = $(this).html();
+                       tofus = detectTofuByImage( text, fontFamily );
+                       for ( i in tofus ) {
+                               callback = 'mw.webfonts.showTofuPopup(' + 
tofus[i].charCodeAt(0) + ', "' + fontFamily + '")';
+                               $tofuPopup = $( '<a>' )
+                                       .prop( { 'href': 'javascript:' + 
callback } )
+                                       .css( { 'text-decoration': 'underline' 
} )
+                                       .text( tofus[i] );
+                               text = text.replace( tofus[i], 
$tofuPopup[0].outerHTML );
+                       }
+                       if ( tofus.length > 0 ) {
+                               $(this).html( text );
+                       }
+               } );
+       };
+}( jQuery, mediaWiki ) );

-- 
To view, visit https://gerrit.wikimedia.org/r/153375
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6f7461a34133e7350a7585bd2a955a7be1b06adc
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/UniversalLanguageSelector
Gerrit-Branch: master
Gerrit-Owner: Xiaoxiangquan <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to