แนะนำ Glyph Protocol สำหรับเทอร์มินัล
(rapha.land)- มีโปรโตคอลเทอร์มินัลแบบใหม่เกิดขึ้นเพื่อแก้ปัญหาเดิมที่ต้อง ติดตั้งฟอนต์แบบแพตช์เอง (เช่น Nerd Font) หากต้องการเรนเดอร์ไอคอนแบบกำหนดเองในแอปพลิเคชันเทอร์มินัล
- Glyph Protocol เป็นโครงสร้างที่ให้แอปพลิเคชัน ลงทะเบียนเวกเตอร์ glyph เข้ากับเทอร์มินัลได้โดยตรงขณะรันไทม์ และสามารถสอบถามได้ว่ารองรับการเรนเดอร์ของ codepoint ใดบ้าง
- ข้อมูล glyph ใช้ฟอร์แมต
glyfของ TrueType ทำให้เทอร์มินัลใช้แรสเตอร์ไรเซอร์ที่มีอยู่แล้วได้ทันที และนำไปใช้ได้โดยไม่ต้องเพิ่ม dependency ใหม่ - จำกัด codepoint ที่ลงทะเบียนได้ไว้ที่ Unicode Private Use Area (PUA) เพื่อป้องกันการโจมตีแบบฟิชชิงและการปลอมภาพลักษณ์ด้วยสายตาตั้งแต่ต้นทาง
- ขณะนี้มีการพัฒนา implementation แรกบน Rio terminal และมีการเผยแพร่โค้ดตัวอย่างสำหรับเฟรมเวิร์ก TUI หลักอย่าง Bubble Tea, Ratatui และ Ink แล้ว
ปัญหาเดิม: การพึ่งพาฟอนต์แบบแพตช์
- หากต้องการให้ terminal editor, prompt และ TUI แสดงไอคอนได้ถูกต้อง ผู้ใช้ต้อง ติดตั้งฟอนต์แบบแพตช์ เช่น Nerd Font หรือ Powerline ด้วยตัวเอง
- หากไม่ได้ติดตั้งฟอนต์ จะเห็น tofu (□) แทนตำแหน่งไอคอน และฟอนต์แบบแพตช์มีขนาดค่อนข้างใหญ่ที่ประมาณ 6~12MB ต่อไฟล์
- JetBrainsMono Nerd Font Regular ประมาณ 7.8MB, FiraCode Nerd Font Regular ประมาณ 10.4MB และ archive สัญลักษณ์ทั้งหมดประมาณ 60MB
- นักพัฒนาแอปพลิเคชันไม่มีวิธีแจกจ่าย glyph ที่ต้องการได้โดยตรง และทำได้เพียงคาดหวังว่าผู้ใช้จะมี ฟอนต์ เวอร์ชัน และการแมป codepoint ที่ถูกต้อง เท่านั้น
ความสามารถหลักของ Glyph Protocol
- รองรับการทำงานหลัก 2 แบบ
- ลงทะเบียน custom glyph: แอปพลิเคชันเลือก Unicode PUA codepoint แล้วส่งเวกเตอร์ outline ไปยังเทอร์มินัลโดยตรงเพื่อลงทะเบียนขณะรันไทม์
- สอบถาม codepoint: สอบถามว่า codepoint ใดถูกครอบคลุมโดย system font, โดยการลงทะเบียนใน session นี้, โดยทั้งสองอย่าง หรือไม่ถูกครอบคลุมเลย
- หากผู้ใช้ติดตั้ง Nerd Font อยู่แล้ว ก็สามารถใช้ผลการสอบถามเพื่อ ข้ามการส่ง glyph ได้ และแม้ยังไม่ได้ติดตั้ง แอปพลิเคชันก็ยังส่ง outline โดยตรงเพื่อให้ แสดงไอคอนได้ตามปกติ
โครงสร้างของโปรโตคอล
วิธีส่งข้อมูล (Transport)
- ใช้ APC (Application Program Command) แทน OSC
- APC ถูกออกแบบมาสำหรับคำสั่งที่แอปพลิเคชันกำหนดเอง และหากเทอร์มินัลยังไม่รองรับ ก็สามารถ เพิกเฉยต่อ sequence นี้ได้อย่างปลอดภัย
- OSC ใช้ global namespace ร่วมกัน โดยมีตัวระบุคำสั่งเป็นเลขฐานสิบเพียงตัวเดียว จึงมีความเสี่ยงต่อการชนกัน แต่ APC ไม่มีปัญหานี้เพราะมีโครงสร้างตัวระบุของตัวเอง
ตัวระบุ (Identifier)
- ทุกข้อความของ Glyph Protocol จะมี codepoint
25a1(U+25A1, WHITE SQUARE) เป็นคำนำหน้า- อักขระนี้คือสัญลักษณ์มาตรฐานของ tofu ที่เทอร์มินัลใช้วาดเมื่อไม่มี glyph
- รูปแบบ framing:
ESC _ 25a1 ; <verb> [ ; key=value ]* [ ; <payload> ] ESC \\ - มี 4 verb:
s(support),q(query),r(register),c(clear)
Support (s): ตรวจสอบว่าเทอร์มินัลรองรับหรือไม่
- ใช้ตรวจสอบว่าเทอร์มินัลรองรับ payload format และ protocol version ใดบ้าง
- นี่คือวิธีมาตรฐานในการตรวจจับด้วยว่า มี Glyph Protocol อยู่หรือไม่
- ค่า
fmtใน response เป็น bitfield โดยแต่ละบิตหมายถึงหนึ่ง payload format1=glyf: TrueType simple glyph, บังคับต้องมีใน v12=colrv0: layered flat color glyph (OpenType COLR v0), เพิ่มใน v1.24=colrv1: full paint graph ที่มี gradient และ transform (OpenType COLR v1), เพิ่มใน v1.2
- หากมี response กลับมา แปลว่ารองรับโปรโตคอล, ถ้า timeout แปลว่าไม่รองรับ, และถ้า
fmt=0แปลว่า implement โปรโตคอลแล้วแต่ยังไม่รองรับ format ใดเลย (นิยามไว้เพื่อความสมบูรณ์)
Query (q): สอบถามว่าสามารถเรนเดอร์ codepoint ได้หรือไม่
- สอบถามว่า codepoint ใดเรนเดอร์ได้หรือไม่ แล้วตอบกลับด้วยค่า
status0(free): ไม่เรนเดอร์อะไรเลย, แสดง tofu1(system): system font ครอบคลุม2(glossary): การลงทะเบียนใน session นี้ครอบคลุม3(both): ครอบคลุมทั้งสองแบบ โดยการลงทะเบียนจะทับการเรนเดอร์จาก system font
- หาก TUI พบว่าในระบบมีไอคอนนั้นอยู่แล้ว ก็สามารถ ข้ามการลงทะเบียน ได้ และหากไม่มี ก็สามารถลงทะเบียน custom codepoint เพื่อ fallback ได้อย่างนุ่มนวล
Register (r): ลงทะเบียน glyph
- แอปพลิเคชันเลือก PUA codepoint แล้วส่ง
glyfoutline ที่เข้ารหัสแบบ base64 เพื่อทำการลงทะเบียน - พารามิเตอร์สำคัญ
cp: codepoint เป้าหมาย (hex), ต้องอยู่ภายใน 3 ช่วงของ Unicode PUA เท่านั้น (U+E000–U+F8FF,U+F0000–U+FFFFD,U+100000–U+10FFFD), หากอยู่นอกช่วงจะถูกปฏิเสธด้วยreason=out_of_namespacefmt: payload format, ใน v1 กำหนดไว้เฉพาะglyfและเป็นค่าเริ่มต้น จึงมักละได้upm: units per em, ใช้กำหนดพื้นที่พิกัดของ outline, ค่าเริ่มต้นคือ 1000
- หากส่ง
rครั้งที่สองให้กับcpเดิม จะเป็นการ เขียนทับการลงทะเบียนก่อนหน้า - หากเกิดข้อผิดพลาด (เช่น codepoint ที่ไม่ใช่ PUA, payload ไม่ถูกต้อง, composite glyph ฯลฯ) จะตอบกลับเป็น
status=<nonzero>; reason=<code>
เหตุผลที่เลือกฟอร์แมต glyf
ทำไมต้องเป็นเวกเตอร์
- glyph ไม่ใช่ภาพถ่าย จึง ไม่มีความละเอียดตายตัว: ไอคอนเดียวกันต้องเรนเดอร์ได้ทั้งใน TUI ความหนาแน่น 12px และจอ HiDPI 24px
- glyph แบบแรสเตอร์จะผูกกับความละเอียดหนึ่งแบบ ทำให้ เบลอบน HiDPI หรืออ่านไม่ออกใน cell ขนาดเล็ก
เหตุผลเฉพาะที่เลือก glyf
- ทุกเทอร์มินัลที่เรนเดอร์ข้อความมี
glyfrasterizer อยู่แล้ว (เช่น FreeType, swash, ttf-parser, fontdue, allsorts) - เมื่อนำ Glyph Protocol มาใช้ ฝั่งเทอร์มินัลจะ ไม่ต้องเพิ่ม dependency ใหม่เลย
- หากเลือก SVG จะต้องดึง
resvgเข้ามาหรือเขียน XML+path parser ใหม่ - ขนาดบนสายส่งก็เล็กกว่า: ไอคอนทั่วไปใช้ข้อมูล
glyfเพียง 150~400 ไบต์ และ เล็กกว่า SVG ที่เทียบเท่ากัน 2~3 เท่า (รวม overhead ของ base64 แล้ว)- เมื่อลงทะเบียนไอคอน 50 ตัว จะต่างกันประมาณ 13KB vs 35KB ซึ่งเห็นผลได้บน tmux pipe หรือ mobile SSH link
คำอธิบายย่อของ glyf
- record ของ
glyfเก็บ glyph เป็น ชุดของเส้นขอบปิด (contour) - แต่ละจุดมีเมทาดาทา 1 บิตว่าเป็น on-curve หรือ off-curve
- จุด on-curve สองจุดติดกัน → เส้นตรง
- มีจุด off-curve อยู่ระหว่าง on-curve → เส้นโค้ง quadratic Bézier
- จุด off-curve สองจุดติดกัน → มีจุด on-curve โดยนัยอยู่ตรงกึ่งกลาง (เทคนิคการบีบอัด)
- พิกัดเป็นตำแหน่งบนกริดจำนวนเต็มภายใน EM square, ที่
upm=1000ค่า(500, 900)หมายถึงกว้างครึ่งหนึ่งและสูง 90% - สามเหลี่ยมปิดหนึ่งรูปมีขนาดประมาณ 30 ไบต์ และไอคอนที่มี 30 จุดมีขนาดประมาณ 200 ไบต์
subset ของ glyf ที่โปรโตคอลกำหนด
- อนุญาตเฉพาะ simple glyph: ใช้ composite glyph, การอ้างอิง glyph อื่น หรือบริบทระดับฟอนต์ไม่ได้
- ใช้ standard flag encoding ตามที่กำหนดใน OpenType spec
- ไม่มี hinting instruction: เพราะ hinting อาศัยชุดค่าควบคุมทั้งฟอนต์ ซึ่งที่นี่ไม่มี
- พื้นที่พิกัดกำหนดโดย
upm, ค่าเริ่มต้น 1000 และ override ได้ในแต่ละการลงทะเบียน
สี การสเกล และการสร้างไฟล์
glyfoutline ไม่มีข้อมูลสี และจะเรนเดอร์ด้วย สี foreground ปัจจุบัน → เหมือนกับกรณีสืบทอดจาก Nerd Font- color glyph รองรับผ่าน payload format แยกคือ
fmt=colrv0/fmt=colrv1 - ค่า
upmเป็นตัวกำหนดพื้นที่พิกัดของ glyph และเทอร์มินัลจะทำการแมปลง cell ตอนเรนเดอร์ → ไม่ต้องลงทะเบียนใหม่เมื่อเปลี่ยนขนาดฟอนต์ - นักพัฒนาส่วนใหญ่จะไม่ได้เขียนไบต์
glyfด้วยตัวเอง แต่จะ แปลงจาก SVG ตอน build time: ใช้อินเทอร์เฟซttx/pensของfonttoolsได้ และมีแผนแจก helpersvg2glyfพร้อม reference implementation ของ Rio
อายุการใช้งานและความจุ
- แต่ละ terminal session จะมี glossary ที่เก็บการลงทะเบียนพร้อมกันได้ สูงสุด 1024 รายการ โดยใช้ codepoint ใน 3 ช่วง PUA เป็นคีย์
- การลงทะเบียนมีผลตลอดอายุของ session
- เมื่อลงทะเบียน glyph ตัวที่ 1025 จะ ไล่รายการเก่าที่สุดออกตามลำดับ FIFO → ไม่มีข้อผิดพลาดแบบ "glossary full"
- แอปพลิเคชันที่ไม่สามารถยอมรับการไล่ออกแบบเงียบ ๆ ได้ ควรสอบถาม codepoint นั้นก่อนส่งออก
ตัวอย่างจริง: ลงทะเบียนไอคอนใน PUA ที่ว่างอยู่
- มีตัวอย่าง pipeline เต็มสำหรับลงทะเบียน stylized outline ไปยัง
U+100000(codepoint แรกของ Supplementary PUA-B) - ใช้
fontToolsเป็นตัวแปลง SVG→glyf - วาด outline ด้วย
TTGlyphPenแล้วเข้ารหัสbase64เพื่อส่งเป็น APC sequence จากนั้นจึงพิมพ์ codepoint ดังกล่าว - payload
glyfของไอคอนทั่วไปที่มี 20 จุดมีขนาดประมาณ 150 ไบต์ และเมื่อรวม APC wrapping กับ base64 แล้วอยู่ที่ประมาณ 250 ไบต์ - สำหรับนักพัฒนาที่มี asset เป็น SVG อยู่แล้ว มีแผนให้ helper
svg2glyfเพื่อให้ลงทะเบียนเสร็จได้ใน 2 บรรทัด
ตัวเลือกสำหรับการลงทะเบียนจำนวนมาก: reply=
- โดยปกติเทอร์มินัลจะส่ง ACK response กลับมาสำหรับทุก
rแต่ใน start hook ที่ลงทะเบียน glyph 100 ตัว จะเกิดปัญหาที่ ACK ที่คิวไว้ 100 รายการไหลออกทาง PTY และแสดงเป็นขยะในเชลล์ - มีการควบคุม 3 ระดับ
reply=1(ค่าเริ่มต้น): ตอบกลับทั้งกรณีสำเร็จและล้มเหลว เหมาะกับการลงทะเบียนทีละรายการแบบโต้ตอบreply=2: ตอบกลับเฉพาะกรณีล้มเหลว ส่วนกรณีสำเร็จจะเงียบ ใช้เมื่อ ต้องการตรวจจับเฉพาะข้อผิดพลาดในการลงทะเบียนจำนวนมากreply=0: ไม่ตอบกลับเลย เป็นแบบ fire-and-forget ใช้ในกรณีอย่าง start hook ที่ไม่มีตัวอ่าน response
- หากกำหนดค่าไม่รู้จัก จะ fallback เป็น
reply=1อัตโนมัติ จึงยังคง backward compatibility สำหรับการขยายในอนาคต
Clear (c): ยกเลิกการลงทะเบียน
- ใช้เมื่อปิด editor เพื่อคืนค่าเริ่มต้นของเทอร์มินัล, เปลี่ยนธีม TUI หรือทำ debugging
- ลบเฉพาะ slot เดียว: ระบุ codepoint เป้าหมายด้วยพารามิเตอร์
cp - ล้าง glossary ทั้งหมด: ไม่ต้องระบุ
cp - การลบ slot ว่างไม่ถือเป็นข้อผิดพลาด แต่เป็น no-op และตอบกลับ
status=0 cpต้องอยู่ในช่วง PUA และหากอยู่นอกช่วงจะคืนค่าreason=out_of_namespace
ความสามารถที่ตั้งใจไม่ใส่ไว้ใน v1
- ไม่สามารถลงทะเบียน codepoint ที่ไม่ใช่ PUA ได้: จำกัดไว้ที่ 3 ช่วงของ Unicode PUA
- ไม่มี ligature: ใช้การลงทะเบียนได้กับ codepoint เดี่ยวเท่านั้น การแทนที่ด้วยลำดับคีย์อยู่นอกขอบเขตของ v1 ส่วน programming ligature (
->→⟶) มี OpenType font จัดการอยู่แล้ว - ไม่มี persistence ข้าม session: ต้องส่ง glyph ใหม่ทุกครั้งที่รัน เพื่อไม่ให้เทอร์มินัลกลายเป็น font cache
- ไม่มีการแชร์ข้ามแอปพลิเคชัน: แต่ละ terminal session มี glossary ของตัวเอง ไม่มี IPC หรือ daemon
- payload
glyfของ v1 ไม่มี color glyph: เรนเดอร์ด้วยสี foreground ส่วนสีถูกแยกไปอยู่ในcolrv0/colrv1ของ v1.2 - ความสามารถเหล่านี้อาจเพิ่มภายหลังได้หากจำเป็น แต่ เมื่อเพิ่มแล้วจะถอดออกได้ยาก จึงตั้งใจตัดออกไว้ก่อน
เหตุผลด้านความปลอดภัยของการจำกัดไว้ที่ PUA
- การจำกัดไว้ที่ PUA ไม่ใช่เรื่องของความสวยงามของ API แต่เป็น คุณสมบัติที่ทำให้เปิดใช้โปรโตคอลเป็นค่าเริ่มต้นได้อย่างปลอดภัย
- หากอนุญาตให้ลงทะเบียน codepoint ใดก็ได้ เช่น ลงทะเบียน glyph รูป
oให้กับU+0061(a) ก็จะทำให้bad.comดูเหมือนbod.comได้- บัฟเฟอร์ของ cell ยังคงเป็น
bad.comดังนั้นเวลา copy/paste ไบต์ยังตรงตามจริง แต่ สิ่งที่ผู้ใช้อ่านเห็นเป็นข้อมูลเท็จ - จะกลายเป็น primitive สำหรับฟิชชิง ที่ใช้ได้กับทุกโปรแกรมเทอร์มินัล และยังส่งผลต่อโปรแกรมที่รันต่อใน session เดียวกันด้วย
- บัฟเฟอร์ของ cell ยังคงเป็น
- หากจำกัดไว้ที่ PUA การโจมตีประเภทนี้จะ เป็นไปไม่ได้ในเชิงกลไก: ผู้ใช้ไม่พิมพ์ PUA codepoint และชื่อไฟล์, URL, คำสั่ง, ชื่อตัวแปร หรือ log ก็ไม่ใส่ PUA codepoint อยู่แล้ว
- เป็นการบังคับใช้ โมเดลความเชื่อถือ ที่ Nerd Font วางธรรมเนียมไว้ในระดับโปรโตคอล (custom glyph อยู่ได้เฉพาะในช่วงที่สงวนไว้ และไม่สามารถทับข้อความจริงได้)
- คุณสมบัติด้านความปลอดภัยเพิ่มเติม
- cell buffer คือแหล่งอ้างอิงที่เชื่อถือได้: การเลือก, คัดลอก, ค้นหา, ตรวจจับ hyperlink, shell history ฯลฯ ต้องคืน codepoint ที่แอปพลิเคชันส่งออกจริง จึงไม่สามารถสร้างกับดักแบบ "เห็นอย่างหนึ่งแต่คัดลอกได้อีกอย่าง" ได้
- แยกกันในระดับ session: สองแท็บสามารถลงทะเบียนไอคอน branch คนละแบบให้
U+E0A0ได้อย่างอิสระ และการลงทะเบียนของแท็บหนึ่งจะไม่กระทบการเรนเดอร์ของอีกแท็บ
เปรียบเทียบกับแนวทางเดิม
Kitty Image Protocol (KIP) + Unicode Placeholders
- สามารถใช้ Unicode placeholder ของ KIP เพื่อเลียนแบบ Glyph Protocol ได้ในระดับหนึ่ง แต่การรวมใช้งานยุ่งยาก และเทอร์มินัลที่รองรับ placeholder มีเพียง Kitty, Ghostty และ Rio
- KIP เป็น image protocol และ glyph ไม่ใช่ภาพ
- ต้นทุนต่อการใช้งาน: glyph ที่ถูกใช้ซ้ำบนหน้าจอ 200 ครั้ง (เช่น ขอบตาราง, bullet marker ฯลฯ) ต้องวาง image reference 200 รายการ ทำให้มีต้นทุนด้าน layout และ composition ขณะที่ Glyph Protocol เมื่อลงทะเบียน codepoint แล้วจะ เรนเดอร์ได้ด้วยความเร็วแบบฟอนต์
- ไม่มี native resolution: outline ของ
glyfไม่มีขนาดพิกเซลตายตัว จึงใช้ได้อัตโนมัติเมื่อเปลี่ยนขนาดฟอนต์ ส่วน KIP ส่ง bitmap ขนาดหนึ่งมา จึง เบลอหรือจำเป็นต้องอัปโหลดใหม่ เมื่อเปลี่ยนขนาด และยังไม่มีวิธีตรวจจับการเปลี่ยนขนาดฟอนต์ - สืบทอดสี foreground: outline
glyfแบบสีเดียวจะเรนเดอร์ตามสี foreground ปัจจุบันของ cell จึง ปรับตามธีมได้อัตโนมัติ ขณะที่ image มีพิกเซลของตัวเองและไม่เข้าร่วมกับการลงสีข้อความ
DEC DECDLD / DRCS
- คือ Dynamically Redefinable Character Sets ที่ VT220 นำมาใช้ในปี 1983 ซึ่งมีรูปแบบคล้าย Glyph Protocol
- แต่มีปัญหาหลัก 2 ข้อ
- เป็นแบบบิตแมป: อัปโหลดกริดพิกเซลที่พอดีกับขนาด cell ปัจจุบันของเทอร์มินัล ดังนั้นเมื่อเปลี่ยนขนาดฟอนต์, ใช้ HiDPI หรือย้ายไปจอ 4K พิกเซลบล็อกจะถูกขยายหรือย่อ เป็นวิธีจากยุค CRT 10×20 แบบคงที่ จึงไม่เหมาะกับ cell หลากหลายขนาดในปัจจุบัน
- ไม่มีการจำกัด namespace: DECDLD สามารถเขียนทับ character set ที่แมปเข้ากับช่วง GL (บริเวณที่มี a, b, c) ได้ ทำให้โปรแกรมที่ไม่น่าเชื่อถือสามารถ นิยามการเรนเดอร์ของ
aใหม่ได้ → นี่คือเหตุผลใหญ่ที่เทอร์มินัลยุคใหม่ไม่อยากเปิดใช้ DECDLD
สถานะการพัฒนาบน Rio terminal
- Glyph Protocol ใช้งานได้แล้วใน main branch ของ Rio terminal และมีแผนจะ land อย่างเป็นทางการภายในเดือนพฤษภาคม → เป็น implementation แรก
- จะมีการเผยแพร่สเปกเต็มพร้อมกับรีลีส รวมถึงโค้ดตัวอย่างสำหรับการลงทะเบียน glyph และการ query เทอร์มินัล
- ตัวอย่างที่ใช้งานได้จริงดูได้จากรีโพ raphamorim/glyph-protocol-examples ซึ่งมีตัวอย่างการรวมกับ Bubble Tea, Ratatui และ Ink
- โปรโตคอลยังอาจมีการอัปเดต และเมื่อมีแอปพลิเคชันกับเทอร์มินัลอื่นเข้าร่วมมากขึ้น รูปแบบข้อความ, query/response และ edge case ต่าง ๆ อาจเปลี่ยนได้ → ตอนนี้ควรมองว่าเป็น moving target และแนะนำให้ตรึงเวอร์ชัน implementation
- ผู้เขียนคาดหวังให้ terminal emulator อื่น ๆ นำไปใช้ด้วย เพราะ ให้ประโยชน์กับ ecosystem โดยรวมมาก ขณะที่ขอบเขตการ implement ตั้งใจให้เล็ก
คำถามเปิดสำหรับชุมชน
- การแจ้งเตือนเมื่อขนาดฟอนต์เปลี่ยนควรอยู่ในขอบเขตของโปรโตคอลหรือไม่?: ตัว Glyph Protocol เองหลีกเลี่ยงปัญหานี้ได้เพราะ outline ไม่ขึ้นกับความละเอียด แต่ TUI ที่ประกอบทั้ง image และ glyph ยังไม่มีทางรู้ว่า cell metric เปลี่ยน นอกจากการ polling → มีการถกเถียงว่าการแจ้งเตือนแบบ
resizeหรือmetrics-changedควรนับว่าอยู่ในขอบเขตหรือเกินขอบเขต - มีวิธีที่รับผิดชอบพอในการอนุญาตการลงทะเบียนนอก PUA หรือไม่?: กฎแบบ PUA-only รับประกันความปลอดภัยพื้นฐาน แต่ก็ปิดกั้นกรณีใช้งานอย่าง IME ภาษาจีน/ญี่ปุ่น/เกาหลีที่ต้องส่ง glyph สำหรับฮั่นอักษรที่ไม่ถูกครอบคลุม หรือเครื่องมือเฉพาะภาษาที่อยาก override glyph → จึงเปิดรับความเห็นว่ามีรูปแบบใดบ้าง เช่น explicit user-level opt-in, ความสามารถแบบ signed, หรือ trusted-source flag ที่จะ รองรับกรณีเหล่านี้ได้โดยไม่เปิดช่องฟิชชิงกลับมาอีก
ยังไม่มีความคิดเห็น