Small Font due to Synthesizing Bug
มีปัญหาหนึ่งที่เจอมาได้พักใหญ่แล้ว คิดว่าหลายคนก็คงเคยเจอ คือปัญหาบางเว็บแสดงตัวอักษรขนาดเล็ก ตัวอย่างหนึ่งที่ผมจำเอาไว้ทดสอบคือ settrade.com อันนี้มีสาเหตุมากจาก CSS ของเว็บเองที่กำหนดฟอนต์ของ <a>
เอาไว้ประมาณนี้ (ตัดมาเฉพาะส่วนที่เกี่ยวข้อง):
font-family: MS Sans Serif, Tahoma, AngsanaUPC, CordiaUPC; font-size: 8pt;
โปรดสังเกตที่ขนาดของฟอนต์.. ขนาด 8pt สำหรับ MS Sans Serif และ Tahoma อาจเป็นขนาดที่พออ่านได้ แต่ขนาด 8pt สำหรับ AngsanaUPC และ CordiaUPC แล้ว หมดสิทธิ์อ่านเลยครับ แล้วก็โชคไม่ดีเสียด้วยที่เราไม่ได้สังเคราะห์ฟอนต์ที่มาก่อน AngsanaUPC เลย AngsanaUPC ก็เลยกลายเป็นฟอนต์ที่ถูกเลือก
เรื่องนี้อาจจะโทษคนทำเว็บก็ได้ ที่ให้ตัวเลือกที่ไม่ดีมา เรื่องนี้ แม้แต่วินโดวส์ที่ถอดเอา MS Sans Serif, Tahoma ออก ก็จะเจอปัญหาเหมือนเราเหมือนกัน แต่เราก็ควรจะแก้ปัญหานี้ได้ ด้วยการทำ alias สำหรับฟอนต์พื้นฐานที่ใช้กันเยอะอย่าง MS Sans Serif และ Tahoma ด้วย เช่น เพิ่มกฎอย่างนี้เข้าไป:
<match target="pattern"> <test qual="any" name="family"> <string>Tahoma</string> </test> <edit name="family" mode="append" binding="same"> <string>Waree</string> </edit> </match>
(สังเกตว่าใช้ <alias>
ประกอบกับ <accept>
จะให้ผลที่ต่างออกไป เพราะรายการที่ accept นั้น จะถูกเพิ่มต่อท้ายแพตเทิร์น คือเสมือนกับใช้ mode="append_last"
ซึ่งจะทำให้ชื่อ Waree มาทีหลัง CordiaUPC เสียอีก ถ้าทำแบบนั้น เราก็จะยังได้ AngsanaUPC อยู่ดี)
แต่ปรากฏว่า หลังจากเพิ่มกฎนี้แล้ว ก็ยังเหลือเซอร์ไพรส์อีก เพราะผลที่ได้ กลายเป็นฟอนต์ Waree ที่ถูกย่อส่วนลง!
ใน thaifonts-scalable มีการสังเคราะห์ฟอนต์ของวินโดวส์บางตัว (ตามบันทึกใน blog เก่า) คือ Angsana, Browallia และ Cordia โดยใช้ฟอนต์แห่งชาติสองตัว คือกินรีกับครุฑ สังเคราะห์สองตัวแรก และใช้ Umpush ของคุณ wd สังเคราะห์ Cordia โดยมีการย่อขนาดลงให้เท่ากับฟอนต์ในวินโดวส์ด้วย
ทีนี้ ปัญหาก็คือ กฎที่เขียนไว้นั้น รองรับแค่กรณีที่ CSS ระบุฟอนต์สังเคราะห์เพียงฟอนต์เดียว โดยแนวคิดของกฎก็คือ ตรวจสอบ match pattern ว่ามีชื่อฟอนต์ที่จะสังเคราะห์หรือเปล่า ถ้ามี ก็แก้ family ให้เป็นฟอนต์ที่มีในลินุกซ์เสีย พร้อมกับกำหนดเมทริกซ์สำหรับย่อขนาดกำกับไว้ด้วย เช่น สำหรับ Angsana ก็เป็นแบบนี้:
<match target="pattern"> <test qual="any" name="family" mode="eq"> <string>AngsanaUPC</string> <string>Angsana New</string> </test> <edit name="family" mode="assign" binding="same"> <string>Kinnari</string> </edit> <edit name="matrix" mode="assign"> <times> <name>matrix</name> <matrix><double>0.67</double><double>0</double> <double>0</double><double>0.67</double> </matrix> </times> </edit> </match>
เมื่อเจอแพตเทิร์นข้างต้นที่มีหลายฟอนต์ โดยมี AngsanaUPC อยู่ในนั้น กฎนี้ก็จะถูกกระทำทันที (เพราะในส่วน <test>
นั้น เราเช็กแบบ "any"
) โดยจะเขียนค่า "Kinnari"
ลงไปแทน "AngsanaUPC"
ที่ match เจอ แถมด้วยเมทริกซ์สำหรับย่อขนาด!
ทีนี้ ถ้าแพตเทิร์นนี้มีแค่ "AngsanaUPC"
อย่างเดียวก็ไม่มีปัญหา เพราะพอเราแก้แพตเทิร์นไปแล้ว มันก็จะไป match เจอ Kinnari แล้วก็มาโดนเมทริกซ์ย่อขนาดลง อันนี้เป็นกรณีที่ผมทดสอบในตอนที่เพิ่มกฎ แต่พอมาเจอกรณีที่แพตเทิร์นมีหลายฟอนต์ ฟอนต์ที่ match เจอ ก็อาจจะได้ฟอนต์อื่นก็ได้ อย่างในกรณีนี้คือ Waree แล้วเราดันเขียนเมทริกซ์ลงในแพตเทิร์นเอาไว้แล้ว Waree ที่ได้ก็เลยโดนย่อส่วนลงด้วยประการฉะนี้
หลังจากนั่งนึก เดินนึกไปมา กฎนี้ไม่สามารถแก้แค่ให้ match แบบ "all"
แทน "any"
ได้ เพราะกฎจะไม่ทำงานเลยในกรณีที่แพตเทิร์นมีหลายฟอนต์ หลังจากลองหลาย ๆ แบบอยู่พักหนึ่ง ก็ได้คำตอบ
วิธีที่ได้ คือแยกกฎออกเป็นสองส่วน ส่วนแรกทำกับ pattern กับส่วนที่สอง ทำกับฟอนต์ที่ match เจอ
ส่วนที่ทำกับ pattern นั้น ก็แค่เติมชื่อ Kinnari ต่อท้าย Angsana เข้าไป ผมเปลี่ยนจากการเขียนทับ เพื่อให้ผู้ใช้ที่ติดตั้ง Angsana ไว้สามารถใช้ Angsana ได้ และผมไม่ใช้ <alias>
ด้วยเหตุผลที่กล่าวไปข้างต้นเกี่ยวกับ Tahoma คือเราต้องการให้ Kinnari ไปแทนที่ Angsana ที่ขาดหายในลำดับที่มีการอ้างถึงเลย
กฎที่ได้ ก็มีรูปแบบเหมือนกับกฎของ Tahoma ข้างต้น:
<match target="pattern"> <test qual="any" name="family"> <string>AngsanaUPC</string> <string>Angsana New</string> </test> <edit name="family" mode="append" binding="same"> <string>Kinnari</string> </edit> </match>
จากนั้น ก็เป็นกฎสำหรับเพิ่มเมทริกซ์ย่อขนาด โดยเขียนกฎที่ target ไปที่ฟอนต์ที่ match เจอ โดยถ้าฟอนต์นั้นเป็น Kinnari ที่ match มาจากแพตเทิร์นที่อ้างถึง Angsana จึงจะกำหนดเมทริกซ์ให้:
<match target="font"> <test name="family" mode="eq"> <string>Kinnari</string> </test> <test target="pattern" qual="any" name="family" mode="eq"> <string>AngsanaUPC</string> <string>Angsana New</string> </test> <edit name="matrix" mode="assign"> <times> <name>matrix</name> <matrix><double>0.67</double><double>0</double> <double>0</double><double>0.67</double> </matrix> </times> </edit> </match>
เพราะฉะนั้น ถ้าโปรแกรมระบุ Kinnari ก็จะได้ Kinnari ขนาดเต็ม แต่ถ้าระบุ Angsana ก็จะได้ Kinnari ที่มีเมทริกซ์ย่อขนาด และการใส่เมทริกซ์นี้ ทำกับฟอนต์ Kinnari ตัวเดียว ไม่ได้ไปกระทบฟอนต์อื่นใน pattern เหมือนกฎเก่า
ทดสอบดูแล้ว สามารถเปิดเว็บที่มีปัญหาข้างต้นได้ โดยได้ฟอนต์ Waree แทนที่ Tahoma โดยไม่มีการย่อส่วน และได้ commit กฎชุดใหม่นี้เข้าใน SVN แล้ว
แต่ข้อจำกัดของกฎนี้คือ ถ้าในกรณีที่ pattern มีทั้ง Angsana และ Kinnari จะถือว่าโปรแกรมต้องการ Angsana เสมอ ผมยังหาวิธีตรวจสอบลำดับก่อนหลังใน pattern ไม่เจอ ถ้าใครมีข้อแนะนำก็แนะนำได้ครับ รวมทั้งอาจจะรายงานกรณีอื่นเข้ามาด้วย เพื่อจะได้ทดสอบและแก้ไขต่อไป
ป้ายกำกับ: thaifonts-scalable, typography