- Computers & electronics
- Software
- Multimedia software
- Graphics software
- Adobe
- InDesign CS4
- User guide
advertisement
▼
Scroll to page 2
of
862
ADOBE® INDESIGN® CS4 ADOBE INDESIGN CS4 PRODUCTS PROGRAMMING GUIDE © 2008 Adobe Systems Incorporated. All rights reserved. Adobe InDesign CS4 Products Programming Guide If this guide is distributed with software that includes an end user agreement, this guide, as well as the software described in it, is furnished under license and may be used or copied only in accordance with the terms of such license. Except as permitted by any such license, no part of this guide may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic, mechanical, recording, or otherwise, without the prior written permission of Adobe Systems Incorporated. Please note that the content in this guide is protected under copyright law even if it is not distributed with software that includes an end user license agreement. The content of this guide is furnished for informational use only, is subject to change without notice, and should not be construed as a commitment by Adobe Systems Incorporated. Adobe Systems Incorporated assumes no responsibility or liability for any errors or inaccuracies that may appear in the informational content contained in this guide. Please remember that existing artwork or images that you may want to include in your project may be protected under copyright law. The unauthorized incorporation of such material into your new work could be a violation of the rights of the copyright owner. Please be sure to obtain any permission required from the copyright owner. Any references to company names in sample templates are for demonstration purposes only and are not intended to refer to any actual organization. Adobe, the Adobe logo, Acrobat, Bridge, Creative Suite, Illustrator, InCopy, InDesign, Photoshop, and Reader are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Apple and Mac OS are trademarks of Apple Computer, Incorporated, registered in the United States and other countries. Java is a trademark of Sun Microsystems, Incorporated in the United States and other countries.All other trademarks are the property of their respective owners. Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, USA. Notice to U.S. Government End Users. The Software and Documentation are “Commercial Items,” as that term is defined at 48 C.F.R. §2.101, consisting of “Commercial Computer Software” and “Commercial Computer Software Documentation,” as such terms are used in 48 C.F.R. §12.212 or 48 C.F.R. §227.7202, as applicable. Consistent with 48 C.F.R. §12.212 or 48 C.F.R. §§227.7202-1 through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being licensed to U.S. Government end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the copyright laws of the United States. Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA. For U.S. Government End Users, Adobe agrees to comply with all applicable equal opportunity laws including, if appropriate, the provisions of Executive Order 11246, as amended, Section 402 of the Vietnam Era Veterans Readjustment Assistance Act of 1974 (38 USC 4212), and Section 503 of the Rehabilitation Act of 1973, as amended, and the regulations at 41 CFR Parts 60-1 through 60-60, 60-250, and 60-741. The affirmative action clause and regulations contained in the preceding sentence shall be incorporated by reference. Contents Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 For experienced InDesign developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 For new InDesign developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Persistent Data and Data Conversion . . . . . . . . . . . . . . . . . . . . . . . . 29 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Persistence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Databases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Persistent objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Using persistent objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Implementing persistent objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 IPMStream methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Implementing a new stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Missing plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Warning levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Missing plug-in alert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Guidelines for handling a missing plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Data handling for missing plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Conversion of persistent data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 When to convert persistent data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Converting data with the conversion manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Converting data without the conversion manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 PluginVersion resource, format numbers, and their macros . . . . . . . . . . . . . . . . . . . . . . 53 Setting up resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Schemas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 SchemaList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 DirectiveList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Advanced schema topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Arrays of values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 FieldArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Conditional-field inclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 3 Contents Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Command pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Databases and undoability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Models. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Command parameters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Command undoability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Command processing and the CmdUtils class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Command sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Command managers, databases, and undo support. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 The command processor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Scheduled commands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Snapshots and interface implementation types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Command history . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Merging changes with an existing step in the command history . . . . . . . . . . . . . . . . . . . 81 Undo and redo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Extension patterns involved in undo and redo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Notification within commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Protective shutdown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Command facades and utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Command-processing APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Error string service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Persistent interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 Persistent boss. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Snapshot interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Inval handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Snapshot view interface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 4 Adobe InDesign CS4 Products Programming Guide Contents Notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101 Observer pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .101 Responder pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Observers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102 Subjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .103 Observers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104 Message protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .104 Subject and observer types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .105 Regular and lazy notification. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .106 Observers and undo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .111 Relating observers to subjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .112 Document notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113 Observers and the model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .113 Responders. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .115 Signal manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116 Responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117 Responders and the model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117 Responders and global error state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118 Ordering of responders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118 Responders and undo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119 Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119 Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120 User-interface widget observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120 Model observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .120 Selection observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122 Document observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122 Active context observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122 Subject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124 Responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .124 Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125 Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125 Selection format and target . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .125 Design patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .126 Selection architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .127 Abstract selection bosses and suites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130 Adobe InDesign CS4 Products Programming Guide 5 Contents Concrete selection bosses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .131 Layout selection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .132 Table selection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .133 Text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .134 Galley text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .135 Story-editor text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136 Note text selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .137 XML selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .138 Document defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140 Application defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141 Integrator suites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142 CSB suites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143 Suites and the user interface: an example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143 Responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144 Basic client-code responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144 Selection-observer responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144 Custom-suite responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144 Custom suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145 Selection extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146 Caches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146 Selection change notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .146 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147 Communication with Integrator suite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147 Selection observers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .147 Selection-utility interface (ISelectionUtils) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148 Layout Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .150 Documents and the layout hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .152 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .152 Parent and child objects and IHierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .155 Spreads and pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .157 Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .161 Layers in a basic document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .162 Layer options. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165 Navigating spread content using ISpread. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .166 6 Adobe InDesign CS4 Products Programming Guide Contents Master spreads and master pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .168 Master spreads and master pages in a basic document . . . . . . . . . . . . . . . . . . . . . . . . .169 Master-page item overrides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172 Basing one master page on another . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172 Page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173 Frames and paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .173 Graphic page items. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .177 Text page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .177 Interactive page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178 Groups. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .178 Abstract page items and kPageItemBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .179 Guides and grids . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180 Ruler guides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180 Margin and column guides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .180 Document grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181 Baseline grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181 Snap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .181 Layout-related preferences. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182 Coordinate systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183 Transformation matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .183 Pasteboard coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184 Inner coordinate space and parent coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . .185 Spread coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .188 Page coordinate space. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .189 Page-item coordinate space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190 Bounding box and IGeometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .190 Transformation and ITransform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .191 Measurement units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .192 Geometrical data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194 The layout presentation and view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194 Layout presentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194 Layout view. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .196 Current spread and active layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197 Layout-presentation and layout-view coordinate spaces . . . . . . . . . . . . . . . . . . . . . . . .198 Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .199 Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .202 New-page-item responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .202 Custom page item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203 Custom unit-of-measure service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .203 Adobe InDesign CS4 Products Programming Guide 7 Contents Commands that manipulate page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204 Page-item creation commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .204 Page-item update commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .205 Page-item deletion commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .209 Graphics Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .211 Path concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .211 Paths data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .213 Path operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .215 Graphic page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .217 Graphic page-item types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .217 Graphic page-item settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .219 Graphic page-item data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223 Graphic page-item examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .226 Graphics import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .238 Export to graphics file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .243 Colors and swatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .246 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .246 Swatches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250 Solid colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .250 Gradients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251 Swatch lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251 Inks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .251 Color management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .252 ICC profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253 Color-management workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253 Data model for color management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .253 Graphic attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256 Graphic-attribute data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256 Representation of graphic attributes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258 Graphic styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258 Graphic state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .259 Mapping graphic attributes between domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .260 Rendering attributes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261 Color-rendering attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .261 Gradient attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262 8 Adobe InDesign CS4 Products Programming Guide Contents Stroke effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262 Path stroker. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .262 Path corners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263 Path-end strokers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263 Transparency effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .263 Flattening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272 Transparency data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .272 Data model for drawing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .276 Presentation views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .276 Graphics context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277 Viewport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .277 Dynamics of drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .278 Drawing the layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .278 Drawing page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .281 Drawing in user-interface widget windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .283 Offscreen drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .284 Client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .285 Path-related client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .285 Graphic page-item client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .286 Key color-related client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .287 Graphic-attribute client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .288 Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289 Custom graphic attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289 Custom path-stroker effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .289 Custom corner effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290 Custom path-end effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .290 Custom page-item adornments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .291 Custom drawing-event handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .294 Swatch-list state. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .296 Initial state of swatch list and ink list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .296 State of swatch list and ink list after adding a custom stop color . . . . . . . . . . . . . . . . . . .297 Swatch list and ink list after adding a gradient swatch. . . . . . . . . . . . . . . . . . . . . . . . . .299 Swatch list and ink list after applying an unnamed color to an object . . . . . . . . . . . . . . . .300 Color spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .300 Catalog of graphic attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .301 Mappings between attribute domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .306 Spread-drawing sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .307 Adobe InDesign CS4 Products Programming Guide 9 Contents Controlling the settings in a graphics port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .309 Drawing sequence for a page item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .310 Text Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313 Text content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315 Stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315 Text formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .324 Class associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .330 Text presentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331 Text layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331 Text frame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .331 Frame list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .333 Threading and text frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .336 Parcels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .339 Span . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342 Text frames and the wax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .343 Text-frame options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .345 Text-frame geometry. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .345 Text Inset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .346 Text wrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .347 Text on a path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .350 The wax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .354 Wax strand, wax line, and wax run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .354 Examples of the wax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355 Text adornments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .358 Text composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .364 Phases of text composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .366 Damage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .367 Recomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .369 Wax strand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .370 Paragraph composers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371 Shuffling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371 Vertical justification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371 Background composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .371 Recomposition transactional model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372 Recomposition notification. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372 Implementation notes for paragraph composers . . . . . . . . . . . . . . . . . . . . . . . . . . . . .372 10 Adobe InDesign CS4 Products Programming Guide Contents Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .389 Font-subsystem architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .390 Fonts within the document. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .392 Composite fonts and international-font issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .395 Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .397 Table structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .397 Design and architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .402 Table model versus text model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .402 Table data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .404 Cell data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .406 Table attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .407 Table and cell styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .409 Formatting tables, cells, and table text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .413 Essential APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .414 Table commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .414 ITableSuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .414 ITableStyleSuite and ITableStylesFacade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .415 ICellStyleSuite and ICellStylesFacade. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .415 Printing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417 Printing is simply drawing to the printer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417 Control can be shared . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417 Inks and colors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .417 Overprinting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .418 Trapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .418 Color management and proofing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .418 Preflight and packaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .418 Exporting to EPS and PDF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419 Printing data model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419 Print settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419 Print preset styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420 Trap styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420 Utility APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .420 The print action sequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .421 Common print interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .422 Adobe InDesign CS4 Products Programming Guide 11 Contents Print user interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423 Print dialog box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .423 Print Presets dialog box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .435 Extending the Print dialog box or the Print Presets selectable dialog box . . . . . . . . . . . . .435 Printing extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .435 Print-setup provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .435 Print-insert-PostScript proc provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .436 Print-data helper-strategy provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .437 Draw-event handlers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .438 Printing solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .438 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .438 Working with print-preset styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .439 Working with trap styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .441 Participating in the print process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .443 Bosses that aggregate IPrintData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .448 Print-action and supporting commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .448 Japanese page-mark files. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .449 Exporting to EPS and PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450 Exporting to EPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .450 Exporting to PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .453 PDF Import and Export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455 PDF import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .455 PDF export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459 InDesign/InCopy document export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .459 InDesign book export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .468 Selected page-items export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .469 PDF-style import and export. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .470 Adding, deleting, and editing styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .471 Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .472 How does the PDF export provider determine whether it should start the viewer after the export? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .472 How do I set the PDF clipboard setting as seen in the File Handling preferences? . . . . . . . .472 How do I control which layer of a document should be exported? . . . . . . . . . . . . . . . . . .472 How do I make the two-page spreads in my document export as two separate PDF pages? .473 Why does kPDFExportCmdBoss give me an assert after the command is processed (ASSERT 'db != nil' in PDFExportController.cpp)? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .473 How do I set up line ranges for output in InCopy Galley or Story mode? . . . . . . . . . . . . . .473 Is it possible to export only selected text from an InDesign document? . . . . . . . . . . . . . .473 12 Adobe InDesign CS4 Products Programming Guide Contents Implementing Preflight Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . 475 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .475 About preflight in InDesign CS4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .475 About rules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .475 Rule IDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476 Rule service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .476 IPreflightRuleService example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .477 Rule bosses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .478 IPreflightRuleVisitor interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .479 IPreflightRuleVisitor method examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .480 IPreflightRuleVisitor::GetClassesToVisit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .480 IPreflightRuleVisitor::Visit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .481 IPreflightRuleVisitor::AggregateResults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .483 IPreflightRuleVisitor::UpdateRuleData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .490 IPreflightRuleVisitor::ValidateRuleData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .490 More on specific objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491 Native, UID-based objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .491 Artwork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .492 Text runs and ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .494 Tables, rows, columns, and cells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .495 XML Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 497 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .497 XML-based workflow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .497 Using XML with InDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .498 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .498 XML features at a glance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499 XML extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499 Tagging in tables and inline graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499 Throw away unmatched existing (right). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .499 Throw away unmatched incoming (left). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Importing repeating elements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Importing CALS table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Support for DOM core level 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Support table- and cell-styles import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Support XML-rules processing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Snippets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .500 Adobe InDesign CS4 Products Programming Guide 13 Contents The user interface for XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501 Structure view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501 Tags in layout view and story view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501 Tags panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .502 Mapping between tags and styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .503 Validation window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .504 Other. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .504 XML model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505 Native document model and logical structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505 Elements and attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .505 Content items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .506 References to elements and content items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .507 Document element and root element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .508 Backing store. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .509 Persistence and the backing store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .510 Importing XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .511 Import architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .512 Importing a minimal XML file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .515 Unplaced content versus placed content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .518 XML template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519 Matching against an XML template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519 Importing repeating elements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .519 Throwing away unmatched existing elements on import (delete unmatched right). . . . . . .520 Throwing away unmatched incoming elements on XML import . . . . . . . . . . . . . . . . . . .522 Attribute-style mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .522 Creating links on XML import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .523 Sparse import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .523 Importing a CALS table as an InDesign table. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524 Support table and cell styles when importing an InDesign table . . . . . . . . . . . . . . . . . . .524 Exporting XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .524 Export architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .525 Document order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .526 Tagged graphic placeholder, exported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .527 Tagged text range, exported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .528 Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .529 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .530 Tag-to-style mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .531 Style-to-tag mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .532 14 Adobe InDesign CS4 Products Programming Guide Contents Elements and content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .534 Tagged graphic placeholder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .534 Tagged images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .536 Tagged stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .537 Tagged text ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .538 Tagged inline graphics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .542 Tagged tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .543 DTD. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .545 Processing instructions and comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .547 Structural (container) elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549 XML-related preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549 Workspace-level XML preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .549 Service-level XML preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .551 Key client API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552 XML suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .552 Command facades and utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .553 Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .553 XML acquirer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .553 XML transformer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .554 XMl-import matchmaker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .555 Post-import responder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .555 Custom suite for the structure view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .556 SAX-content handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .556 SAX DOM serializer handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557 Custom-tag service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557 SAX-entity resolver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557 XML-export handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .558 Commands and notification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .558 Backing store and notification of changes in logical structure. . . . . . . . . . . . . . . . . . . . .558 Entities supported . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .559 Assets from XSLT example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .560 Limitations of the InDesign XML architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .561 Adobe InDesign CS4 Products Programming Guide 15 Contents Scriptable Plug-in Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . 563 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .563 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .565 Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .565 Benefits of making a plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .565 Scripting and IDML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .566 Making a plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .566 Tools for making a plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .567 Scripting architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .567 Scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .568 Versioning the scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .569 Scripting plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .570 Script interaction with the scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .571 Scripting process overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .572 Script managers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .573 Scriptable plug-ins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .573 Scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .574 Script providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .574 Scriptable boss classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .574 How to make your plug-in scriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .575 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .575 Defining IDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .576 Adding a new property to an existing script object . . . . . . . . . . . . . . . . . . . . . . . . . . .576 Adding a new event to an existing script object . . . . . . . . . . . . . . . . . . . . . . . . . . . . .576 Adding a new script object to make preferences scriptable . . . . . . . . . . . . . . . . . . . . . .577 Adding a new singleton script object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .578 Adding a new script object to make a boss with a UID scriptable. . . . . . . . . . . . . . . . . . .578 Adding a new script object to make a boss with no UID scriptable. . . . . . . . . . . . . . . . . .579 Adding a new script object to make a C++ object with no boss scriptable . . . . . . . . . . . . .580 Adding a new script object to make a panel scriptable . . . . . . . . . . . . . . . . . . . . . . . . .581 Adding an error-string service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .582 Handling multiple concurrent requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .582 Reviewing scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .583 Running versioned scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .586 Supporting IDML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .588 Maintaining IDML forward and backward compatibility . . . . . . . . . . . . . . . . . . . . . . . .589 Verifying your plug-in’s data is round-tripped through IDML . . . . . . . . . . . . . . . . . . . . .590 Tips for debugging the scripting architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .591 16 Adobe InDesign CS4 Products Programming Guide Contents Scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .591 VersionedScriptElementInfo resource . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .592 Object element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .593 Event element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .595 Property element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .597 Struct element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .601 TypeDef element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .602 Enum element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .603 Enumerator element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .604 Metadata element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .604 Provider element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .606 Suite element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .609 ScriptElementIDs, ScriptIDs, names, descriptions, and GUIDs . . . . . . . . . . . . . . . . . . . . .610 ScriptID/name registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .612 Scripting data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .615 Script-object inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .619 Overloading an existing event or property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .621 Versioning of scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .621 Client-specific scripting resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .632 Elements that are not applicable to a particular object . . . . . . . . . . . . . . . . . . . . . . . . .638 Key scripting APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .639 Scripting DOM reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .641 Scripting DOM versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .641 Dumping the scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .642 Snippet Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643 Conceptual overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .643 Snippets as self-contained assets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .643 Snippet types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644 Features that depend on snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644 User interface for snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644 Drag and drop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .644 Asset library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645 Export snippet from selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645 Snippet model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645 INX, IDML, and snippets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645 Boss DOM overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .646 Scripting DOM overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .647 From boss DOM to scripting DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .647 Adobe InDesign CS4 Products Programming Guide 17 Contents Snippet types and policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .648 Export . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .648 Import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .650 Snippet examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .652 Filled-rectangle snippet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .652 Image-item snippet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .657 XML element snippet, tagged placeholder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .660 Client API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .663 Suites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .663 Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .663 Extension patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664 Adding persistent data to snippet files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664 Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664 What is a snippet, and how do I create one? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .664 What happens if I export a snippet of a placed image? . . . . . . . . . . . . . . . . . . . . . . . . .664 What features are based on snippets? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665 How accurately is data round-tripped through snippets?. . . . . . . . . . . . . . . . . . . . . . . .665 When do I have to care about snippets?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665 Can I export spreads or pages as snippets?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665 Should we generate snippet files from scratch? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .665 Can I import a snippet directly into a library? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .666 Can I import a snippet into the scrap database? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .666 Can we add our own new snippet types? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .666 Shared Application Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . 667 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .667 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .667 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .667 How it works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .668 ISnippetExport. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .668 IAppPrefsExportDelegate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .669 ISnippetImport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .669 IAppPrefsImportOptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .669 IAppPrefsImportDelegate. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .670 18 Adobe InDesign CS4 Products Programming Guide Contents Working with snippet APIs: frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . .670 How do I create streams for reading and writing snippets?. . . . . . . . . . . . . . . . . . . . . . .670 How do I limit my export to those items in the preference panel? . . . . . . . . . . . . . . . . . .670 How do I export all text styles, object styles, XML tags, or swatches in the application workspace? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671 How do I import a snippet into the application? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671 How do I control whether existing objects like paragraph styles are replaced or deleted on import. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671 How do I determine the correct ScriptID to use for a preference I’m trying to include or exclude? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .671 How do I know which list element types will be exported by default?. . . . . . . . . . . . . . . .671 User-Interface Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .673 Key concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .674 Design objectives for user-interface API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .674 Idioms and naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .674 Abstractions and re-use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .675 Widgets versus platform controls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .676 Commands, model plug-ins, and user-interface plug-ins . . . . . . . . . . . . . . . . . . . . . . .676 Suites and the user interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .677 Finding widgets in the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .678 Notifications about control events or changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .678 Sample user interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .679 Type binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .680 Factorization of the user-interface model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .683 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .683 Control views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .684 Control data models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .684 Event handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .685 Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .685 Relevant design patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .686 Observer pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .686 How event handlers implement controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .687 The role of MVC in the user-interface model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .688 Chain of responsibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .689 Facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .689 Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .690 Widget-observer pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .690 Persistence and widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .691 Adobe InDesign CS4 Products Programming Guide 19 Contents Resource roadmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .692 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .692 OpenDoc framework (ODF) resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .693 Top-level framework resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .694 Localizing framework resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .694 Resource compilers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .695 Customizing a widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .696 Advanced event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .696 Writing a proxy event handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .696 Watching events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .697 Key abstractions in the API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .697 Suppressed User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .699 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .699 XML-based implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .700 XML file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .701 SuppressedWidget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .702 SuppressedAction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .702 SuppressedMenu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .703 SuppressedDragDrop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .703 SuppressPlatformDialogControl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .704 SuppressedUI tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .704 SuppressedUI tool limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .706 Working with the ISuppressedUI API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .706 Other user-interface “suppression” mechanisms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .707 Using Adobe File Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 709 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .709 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .709 Adobe File Library architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .711 Adobe File Library classes and utilities. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .711 Common file API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .713 File API specific to InDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .714 Debugging IDFile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .716 Porting guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .716 Creative Suite 2 porting concerns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .716 Creative Suite 3 porting concerns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .716 20 Adobe InDesign CS4 Products Programming Guide Contents Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .717 Why should I use Adobe file library? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .717 Does Adobe file library support cross-platform path conversion? . . . . . . . . . . . . . . . . . .717 Should I still use the ICoreFileName interface? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .717 Why was the GetSysFile method renamed GetIDFile in SDKFileHelper? . . . . . . . . . . . . . . .717 How do I navigate between IDFile and IDPath? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .717 What are the differences between a file and a directory? . . . . . . . . . . . . . . . . . . . . . . . .718 What are the relationships between IDPath and IDFile? . . . . . . . . . . . . . . . . . . . . . . . . .718 Why should IDFile not be treated as PMString? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .718 How do an invalid path and a nonexistent path differ? . . . . . . . . . . . . . . . . . . . . . . . . .718 Can I construct an AString from PMString? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .718 How can I convert a relative path to an absolute path? . . . . . . . . . . . . . . . . . . . . . . . . .719 Performance Tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721 Use profiling tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .721 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .721 Mac OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .721 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .722 Commands should operate on lists of inputs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .722 Notify on the document subject instead of the page item object . . . . . . . . . . . . . . . . . .722 Mark commands that do not require undo support . . . . . . . . . . . . . . . . . . . . . . . . . . .723 Observers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .723 Attach to documents, not page items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .723 Do work only when the command is done . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .723 Do not update the user interface from an observer . . . . . . . . . . . . . . . . . . . . . . . . . . .724 Watch for lazy notification whenever possible. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .724 File input/output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .724 Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .724 Use memory caches for items accessed often . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .724 Avoid allocating too much memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .725 Idle tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .725 Honor the RunTask flags. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .725 Do a small amount of work during each RunTask call . . . . . . . . . . . . . . . . . . . . . . . . . .725 Adobe InDesign CS4 Products Programming Guide 21 Contents Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 Key concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .727 The toolbox and the layout view . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .727 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .728 Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .728 Tool tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .729 Trackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .729 Tracker factory, tracking, and event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .729 Beyond the toolbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .730 Drawing and sprites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .730 Documents, page items, and commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .731 Line-tool use scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .731 Trackers with multiple behaviors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .734 Tool manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .735 Toolbox utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .735 Tool type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .735 Custom tools. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .736 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .736 Class diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .736 Partial implementation classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .737 Default implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .737 ToolDef ODFRez type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .738 Icons and cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .738 InDesign trackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .739 Working with tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740 Catching a mouse click or mouse drag on a document . . . . . . . . . . . . . . . . . . . . . . . . .740 Implementing a custom tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740 Displaying a Tool Options dialog box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740 Finding the spread nearest the mouse position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740 Changing spreads. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740 Performing a page-item hit test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .740 Setting or getting the active tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .741 Observing when the active tool changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .741 Changing the toolbox appearance from normal to skinny . . . . . . . . . . . . . . . . . . . . . . .741 Using default implementations for trackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .741 Suppressing the application's default tracker for a custom toolbox . . . . . . . . . . . . . . . . .741 Tool-category information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .742 Default implementations of tool-related interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .745 Tracker listings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .746 22 Adobe InDesign CS4 Products Programming Guide Contents Diagnostics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .751 Using the diagnostics plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .751 Diagnostics menu. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .752 Diagnostics > Command menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .752 Diagnostics > Document Structure menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .753 Diagnostics > INX DTD menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .754 Diagnostics > Object Model menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .755 Diagnostics > Scripting DOM menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .756 Running the Diagnostics plug-in in indesign/incopy with a script . . . . . . . . . . . . . . . . . .756 Running the Diagnostics plug-in in InDesign Server on Windows with a script . . . . . . . . . .757 Running the Diagnostics plug-in in InDesign Server on Mac OS with a script . . . . . . . . . . .757 Frequently asked questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .758 Where is the Diagnostics panel?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .758 What is trace? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .758 Why don’t I get trace messages? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .758 InCopy: Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759 About InCopy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .759 Developing for InCopy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .759 Using the combined InDesign/InCopy SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .759 The InCopy API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .760 Compiler settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .760 Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .760 Synchronization of design and architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .760 File relationships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .761 Stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .762 Page geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .762 Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .762 The document model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .763 User-interface differences. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .763 Checking the feature set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .763 Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .764 Design and architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .764 InCopyBridge plug-in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .766 InCopyBridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .766 InCopyBridgeUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .767 Adobe InDesign CS4 Products Programming Guide 23 Contents InCopy: Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 769 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .769 End-user requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .769 Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .771 Data model for notes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .773 Essential APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .779 Useful commands and associated notification protocols . . . . . . . . . . . . . . . . . . . . . . . .783 Working with notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .786 Adding a note at the current insertion-point position . . . . . . . . . . . . . . . . . . . . . . . . . .786 Inserting text into a note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .787 Converting text to a new note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .787 Converting note content to text. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .787 Navigating among notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .788 Splitting a note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .788 Expanding and collapsing notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .788 Selecting a note . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .789 Getting kNoteDataBoss, given a text index whose position is anchored to note . . . . . . . . .789 Deleting notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790 Changing notes-palette content to reflect particular note data . . . . . . . . . . . . . . . . . . . .790 Checking note spelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790 Observing a note that is being modified . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790 Using notes in InDesign . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .790 InCopy: Track Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .791 User interface for Track Changes feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .791 Data model for Track Changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .794 Redline strand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .794 Tracking text insertion and deletion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .795 Example: Track Changes in action. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .799 Track Changes preferences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809 Key client APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809 Track Changes utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809 Suite interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .809 RedlineIterator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .811 kDeletedTextBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .812 24 Adobe InDesign CS4 Products Programming Guide Contents Useful commands and associated notification protocols . . . . . . . . . . . . . . . . . . . . . . . . . . .814 kSetRedlineTrackingCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .814 kSetTrackChangesPrefsCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .814 kActivateRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .816 kDeactivateRedlineCmdBoss. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .816 kRejectAllRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .816 kRejectRangeRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .817 kRejectRedlineCmdBoss. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .817 kAcceptAllRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .818 kAcceptRangeRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .819 kAcceptRedlineCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .819 kMoveRedlineChangeCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .820 kRedlinePreserveDeletionCmdBoss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821 Working with Track Changes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821 Navigating tracked changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821 Accepting and rejecting tracked changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .821 Understanding multiple change records in one location . . . . . . . . . . . . . . . . . . . . . . . .822 Avoid insignificant tracked changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .822 Undoing accepted deleted text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .822 Determining whether a location in a story is in deleted text . . . . . . . . . . . . . . . . . . . . . .822 Determining whether a primary story-thread location is at a deleted-text anchor . . . . . . . .822 Getting kDeletedTextBoss, given a text index having deleted text . . . . . . . . . . . . . . . . . .823 Removing deleted text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .823 Moving a change record from one story to another . . . . . . . . . . . . . . . . . . . . . . . . . . .823 Maintaining kRedlineStrandBoss text-run information . . . . . . . . . . . . . . . . . . . . . . . . .823 InCopy: Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825 Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .825 Assignment workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .826 Assignment-export options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .826 Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .827 Assignment data model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .829 Assignment hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .829 Object structure of an assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .830 Moving assignment content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .832 Assignment files and links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .834 Assignment files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .834 Comparing assignment files to InDesign and InCopy files . . . . . . . . . . . . . . . . . . . . . . .835 Assignment-file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .835 Adobe InDesign CS4 Products Programming Guide 25 Contents The assignment API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838 IAssignmentMgr. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838 IAssignedDocument . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838 IAssignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838 IAssignedStory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .838 IAssignmentSelectionSuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839 IAssignmentUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839 IAssignmentUIUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839 IAssignmentPreferences. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839 Common commands. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .839 Glossary 26 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 841 Adobe InDesign CS4 Products Programming Guide Introduction For experienced InDesign developers Introduction This guide provides detailed information on the Adobe® InDesign® CS4 plug-in architecture. This C++-based SDK can be used for creating plug-ins compatible with the CS4 versions of InDesign, InDesign Server, and Adobe InCopy®. This guide contains the most detailed information on plug-in development for InDesign products. It is not designed to be a starting point. It picks up where Learning Adobe InDesign CS4 Plug-in Development leaves off, and it is more commonly used to understand particular subjects deeply. For experienced InDesign developers If you are an experienced InDesign plug-in developer, we recommend starting with Adobe InDesign CS4 Porting Guide. For new InDesign developers If you are new to InDesign development, we recommend approaching the documentation as follows: 1. Getting Started With the Adobe InDesign CS4 Products SDK provides an overview of the SDK, as well as a tutorial that takes you through the tools and steps to build your first plugin. 2. Learning Adobe InDesign CS4 Plug-in Development introduces the most common programming constructs for InDesign development. This includes an introduction to the InDesign object model and basic information on user-interface options, scripting, localization, and best practices for structuring your plug-in. 3. The SDK itself includes several sample projects. All samples are described in the “Samples” section of the API reference. This is a great opportunity to find sample code that does something similar to what you want to do, and study it. 4. Adobe InDesign CS4 Solutions provides step-by-step instructions (or “recipes”) for accomplishing various tasks. If your particular task is covered by the Solutions guide, reading it can save you a lot of time. 5. This manual provides the most complete, in-depth information on plug-in development for InDesign CS4 products. Introduction 27 Introduction For new InDesign developers 28 Persistent Data and Data Conversion Concepts Persistent Data and Data Conversion This chapter describes how an application stores and refers to persistent data as objects and streams. The chapter also provides background information and implementation guidelines related to data conversion. This chapter has the following objectives: z Describe how Adobe InDesign® stores data. z Explain how an object is made persistent. z Show how to refer to a persistent object. z Define a stream and explain how to create a new stream. z Identify when data conversion is used. z Describe the types of conversion providers. z Show how conversion providers are defined. z Describe schemas and their use. For common procedures and troubleshooting related to converting persistent data, see the “Versioning Persistent Data” chapter of Adobe InDesign CS4 Solutions. Concepts Persistence A persistent object can be removed from main memory and returned again, unchanged. A persistent object can be part of a document (like a spread or page item) or part of the application (like a dialog box, menu item, or default setting). Persistent objects can be stored in a database, to last beyond the end of a session. Non-persistent objects last only until memory is freed, when the destructor for the object is called. Only persistent objects are stored in databases. Databases The application uses lightweight databases to store persistent objects. The host creates a database for each document created. The host also creates a database for the clipboard storage space, the object model information (the InDesign SavedData or Adobe InCopy® SavedData file), and the workspace information (the InDesign Defaults or InCopy Defaults file). Each document is contained in its own database. Each persistent object in the database has a UID, a ClassID, and a stream of persistent data. The stream with the persistent object data contains a series of records that correspond to the persistent object. The object’s UID is stored with the object, as a key for the record. The vari- Persistent Data and Data Conversion 29 Persistent Data and Data Conversion Persistent objects able-length records have one segment for each persistent interface. Every segment has the same structure: ImplementationID tag int32 length <data> Figure 1 is a conceptual diagram of this structure. The figure is a conceptual diagram of the database contents, and does not represent the actual contents of any database. The format and content of the data are determined by the implementation of the interface. See “Reading and writing persistent data” on page 34. FIGURE 1 Conceptual diagram of an object’s data k<Foo>Boss object persistent data record UID ImplID Length Data ImplID Length Data ImplID Length For each object, the ClassID value is stored in the table, and the ImplementationID values are stored in the stream, but the InterfaceID value is not stored with either. Adding an existing implementation (i.e., an implementation supplied by the SDK) to an existing class can cause problems if another software developer adds the same implementation to the class: one of the two plug-ins will fail on start-up. To avoid this collision, create a new implementation for any persistent interface to be added to a class, using ImplementationAlias. For an example, see <SDK>/source/sdksamples/dynamicpanel/DynPn.fr. Persistent objects This section discusses how persistent objects are created, deleted, and manipulated. The application stores persistent objects in a database, and each object has a unique identifier within the database. The methods for creating, instantiating, and using a persistent object are different from the methods for non-persistent objects. Using persistent objects When a persistent object is created, its record exists in memory. Certain events, like a user’s request to save a document, trigger the writing of the record to storage. (See Figure 2) A count is maintained of the number of references to each persistent object. Any object with a reference count greater than zero remains active in memory. If the reference count for a persistent object reaches zero, the object may be asked to write itself to its database and be moved to the instance cache, which makes the object a candidate for deletion from memory. Events that require access to the object, like drawing or manipulating it, trigger the host to read the object back 30 Persistent Data and Data Conversion Persistent objects into memory. Because individual objects can be saved and loaded, the host does not have to load the entire document into memory at once. FIGURE 2 Creating and storing persistent objects Host Main memory Storage NewUID Instantiate (no storage) Dirty ReadWrite Reference count reaches zero Instantiate (with storage) Creating a persistent object Creating a new instance of a persistent object differs from creating a non-persistent object, because it requires a unique identifier to associate the object with its record in the database. For the CreateObject and CreateObject2 methods used to create persistent objects, see <SDK>/source/public/includes/CreateObject.h. For examples of the creation of persistent objects, see the CreateWidgetForNode method in <SDK>/source/sdksamples/paneltreeview/PnlTrvTVWidgetMgr.cpp or the StartupSomePalette method in <SDK>/source/sdksamples/dynamicpanel/DynPnPanelManager.cpp. You also can call IDataBase::NewUID method to create a new UID in the database. It adds an entry to the database relating the UID to the class of the object being created; however, the object is not instantiated yet, and no other information about it exists in the database. Instantiating a persistent object Before you instantiate a new object, use the InterfacePtr template to retrieve one of the object’s interfaces. Pass the returned InterfacePtr to the IDatabase::Instantiate method, which calls the database to instantiate the object. There is only one object in memory for any UID and database. This method checks whether the object already is in memory and, if so, returns a reference to that object. If the object is Persistent Data and Data Conversion 31 Persistent Data and Data Conversion Persistent objects marked as changed, it is written to the database. For more information, see “Reading and writing persistent data” on page 34. If the object is not in memory, the method checks for previously stored data in the database. If data is found, the method instantiates the object from this data. Otherwise, the method instantiates the object from the object’s constructor. Each implementation has a constructor, so the boss and all its implementations are instantiated. An object is stored to the database only if it is changed, making the default object data invalid. A single object could exist and be used in several user sessions without ever being written to the database. A persistent object whose data is not stored in the database is constructed from the object’s constructor. Whether it instantiates a new object or returns a reference to an object previously instantiated, IDatabase::Instantiate increments the reference count on the object and returns an IPMUnknown* to the requested interface, if the interface is available. Using commands and wrappers There are commands for creating new objects of many of the existing classes (e.g., kNewDocCmdBoss, kNewPageItemCmdBoss, kNewStoryCmdBoss, and kNewUIDCmdBoss). When you need to create an object, first look for a suite interface, utility interface, or facade interface to make creating your object safe and easy. If no such interface exists, use a command if one is available, rather than creating the object with general functions. Using a command to create an object protects the database. Commands are transaction based; if you use a command when the application already is in an error state, the command performs a protective shut-down, which quits the application rather than permitting a potentially corrupting change to be made to the document. Commands also provide notification for changes to the model, allowing observers to be updated when the change is made, including changes made with undo and redo operations. When you implement a new type of persistent object, also implement a command to create objects of that type, using methods outlined in “Implementing persistent objects” on page 33. Types of references to objects There are four types of reference to a persistent object: UID, UIDRef, InterfacePtr, and UIDList. Each type of reference serves a different purpose. Understanding these reference types makes working with persistent objects easier. 32 z UID is the type used for a unique identifier within the scope of a database. The UID value by itself is not sufficient to identify the object outside the scope of the database. Like a record number, a UID value has meaning only within a given database. UID values are useful for storing, passing, and otherwise referring to boss objects, because UID values have no run-time dependencies, and there is an instance cache ensuring fast access to the instantiated objects. kInvalidUID is a value used to identify a UID that does not point at a valid object. Any time a UID is retrieved and needs to be tested to see if it points at a valid object, the UID should be compared to kInvalidUID. z A UIDRef object contains two pieces of information: a pointer to a database and the UID of an object within this database. A UIDRef is useful for referring to objects, because it identifies both the database and the object. Using a UIDRef object is a common means of referring to a persistent object, especially when the persistent object is to be passed around or Persistent Data and Data Conversion Persistent objects stored, since a UIDRef does not require the referenced object to be instantiated. A UIDRef object cannot itself be persistent data, because it has a run-time dependency, the database pointer. An empty or invalid UIDRef object has kInvalidUID as its UID and a nil pointer as its database pointer. z A InterfacePtr object contains a pointer to an interface (on any type of boss object) and identify an instantiated object in main memory. While an InterfacePtr object on the boss is necessary for working with the boss, it should not be used to track a reference to a persistent object, because this forces the object to stay in memory. In many cases, a nil pointer returned from InterfacePtr does not indicate an error state but simply means the requested interface does not exist on the specified boss. z A UIDList object contains a list of UIDs and a single pointer to a database. This means all objects identified by a UIDList must be within the same database. A UIDList is a class object and should be used any time a list of objects is needed for a selection or a command. Destroying an object There are commands for deleting persistent objects. Use the command rather than calling the DeleteUID method directly, to be sure of cleaning up all references to the object or item references contained in the object. When you implement a command to delete a persistent object, after you remove the references to the object, use DeleteUID to delete the object from the database, as follows: IDataBase::DBResultCode dbResult = database->DeleteUID(uid); Implementing persistent objects To make a boss object persistent, add the IPMPersist interface. Any boss with this interface is persistent and, when an object of the boss is created, it is assigned a UID. Even though the object has a UID, and the UID has an entry in the (ClassID, UID) pairings in a database, the object does not automatically store data. It is up to the interface to store the data it needs. To implement this, add the ReadWrite method to the interface (see “Reading and writing persistent data” on page 34), and make sure the PreDirty method is called before information is changed (see “Marking changed data” on page 34). NOTE: If you add an interface to an existing persistent boss, the interface also may be made persistent. If so, you must obey the following implementation rules for it. Adding the IPMPersist interface to a boss All instances of IPMPersist must use the kPMPersistImpl implementation. For an example, see the kPstLstDataBoss boss class definition in <SDK>/source/sdksamples/persistentlist/PstLst.fr Creating an interface factory for a persistent interface For a persistent implementation, use the CREATE_PERSIST_PMINTERFACE macro. Persistent Data and Data Conversion 33 Persistent Data and Data Conversion Streams Reading and writing persistent data To store data, your interface must support the ReadWrite method. This method does the actual reading and writing of persistent data in the database. The method takes a stream argument containing the data to be transferred. Read and write stream methods are generalized, so one ReadWrite method handles transfers in both directions. For example, XferBool reads a boolean value for a read stream and writes a boolean value for a write stream. For an example, see the BPIDataPersist::ReadWrite method in <SDK>/source/sdksamples/basicpersistinterface/BPIDataPersist.cpp. Marking changed data When data changes for a persistent object that resides in memory, there is a difference between the current version of the object and the object as it exists in the database’s storage. When this happens, the object in memory is said to be dirty, meaning it does not match the version in storage. Before a persistent object is modified, you must call the PreDirty method to mark the object as being changed, so it is written to the database. For an example, see the BPIDataPersist::Set method in <SDK>/source/sdksamples/basicpersistinterface/BPIDataPersist.cpp. The PreDirty method called from within BPIDataPersist::Set is implementation-independent, so you can rely on the version provided by HELPER_METHODS macros defined in HelperInterface.h (DECLARE_HELPER_METHODS, DEFINE_HELPER_METHODS, and HELPER_METHODS_INIT). Streams This section discusses how streams are used to move information into and out of a document. Streams are used by persistent objects to store their information to a database. Streams also are used by the host application, to move data like placed images, information copied to the clipboard, and objects stored in the database. IPMStream is the public interface to streams. Implementations of IPMStream typically use the IXferBytes interface to move data. Stream utility methods (in StreamUtil.h) are helpers for creating all the common types of streams used to move information within or between InDesign databases. The stream utility methods and general read, write, and copy methods are needed any time you work with a stream. IPMStream methods IPMStream is a generalized class for both reading and writing streams. Any particular stream implementation is either a reading stream or a writing stream, and the type of stream can be determined with the IPMStream::IsReading and IPMStream::IsWriting methods. Any persistent implementation has a ReadWrite method, which uses a set of data-transferring methods on the stream to read and write its data. (See “Reading and writing persistent data” on page 34.) The IPMStream methods starting with the Xfer prefix are used for transferring the 34 Persistent Data and Data Conversion Streams data type identified in the method name. For example, XferByte transfers a byte, XferInt16 transfers a 16-bit integer, XferBool transfers a boolean value, and so on. All transferring methods are overloaded, so they can take a single item or an array of items. (The XferByte(uchar, int32) version typically is used for buffers.) Streams also handle byte swapping, if required. If swapping is not set (SetSwapping(bool16)), the default is to not do byte-order swapping. Additional IPMStream methods, XferObject and XferReference, transfer boss objects and references to objects. XferObject transfers an owned object, and XferReference transfers a reference to an object not owned by the object using the stream. To decide which method to use, think about what should happen to the object if the owning object were deleted. If the object should still be available (as, for example, the color a page item refers to), use XferReference. If the item is owned by the object and should be deleted with the owner (as, for example, the page a document refers to), use XferObject. Implementing a new stream If you must read from or write to a location the host application does not recognize, you must create a new type of stream. For example, you might need to create a new stream type to import and export files stored on an FTP site or in a database. Stream boss The first step in implementing a new stream is to define the boss. Typically, a stream boss contains IPMStream and any interface required to identify the type of information in the stream, the target or source of the stream, or both. Example 1creates a pointer-based read-stream boss: EXAMPLE 1 kExtLinkPointerStreamWriteBoss, a pointer based stream boss Class { kExtLinkPointerStreamWriteBoss, kInvalidClass, { IID_IPMSTREAM, kExtLinkPointerStreamWriteImpl, IID_IPOINTERSTREAMDATA, kPointerStreamDataImpl, } }; IPMStream is the only interface all stream bosses have in common. In Example 1, the IPointerStreamData controls a stream that writes out to memory; it contains a buffer and a length. Persistent Data and Data Conversion 35 Persistent Data and Data Conversion Missing plug-ins Example 2 is another example. EXAMPLE 2 kFileStreamReadBoss, a stream commonly used in importing Class { kFileStreamReadBoss, kInvalidClass, { IID_IPMSTREAM, kFileStreamReadLazyImpl, IID_IFILESTREAMDATA, kFileStreamDataImpl, } }; IPMStream interface and the IXferBytes class When implementing your own stream, take advantage of the default implementations of IPMStream, CStreamRead, and CStreamWrite. These default implementations use an abstract base class, IXferBytes, to do the actual reading and writing. To implement a stream for a new data source, you must create an IXferBytes subclass that can read and write to that data source. Missing plug-ins This section discusses how to open a document that contains data saved by a plug-in that is no longer available. Plug-ins you create can add data to the document. When your plug-in is present and loaded, it can open and interpret the data; however, if the user removes the plug-in and then opens the document, or gives the document to someone who does not have the plug-in, the plug-in is not available to interpret the data. You have two ways to handle such situations: z Control what warning is shown when the document is opened without the plug-in. z Implement code to update the data the next time the document is opened with the plug-in. The rest of this section describes these options. Warning levels The application can give a warning when it opens a document that contains data created by a plug-in that is not available. There are three warning levels: critical, default, and ignore. By setting the warning level, the plug-in can specify the relative importance of its data. Data created by the plug-in has the “default” warning level unless you override the setting and identify the data as more important (critical) or less important (ignored). This importance settings can be modified by adding resources to the plug-in’s boss definition file: z 36 CriticalTags — A “critical” warning tells the user the document contains data from missing plug-ins and strongly advises the user not to open the document. If the user continues the Persistent Data and Data Conversion Missing plug-ins open operation, the application opens an untitled document that is a copy of the original, to preserve the original document. Use this level when the data is visible in the document or contributes objects owned by another object in the database, like text attributes, owned by the text model. z DefaultTags — A “default” warning tells the user the document contains data from missing plug-ins and asks whether to continue the open operation. If the user continues the open operation, the application opens the original document. Use this level when the data is selfcontained and invisible to the user, but the user might encounter missing function that would have been provided by the plug-in. z IgnoreTags — An “ignore” warning provides no warning message at all; the application proceeds with the open operation as if there were no missing plug-ins. Use this level when the data is invisible to the user and completely self-contained. In this case, the user does not need to know the plug-in was involved in the construction of this document. If the plug-in stored data in the document, but that data is used only by this plug-in and does not reference objects supplied by other plug-ins, the user sees no difference in the document when the plug-in is missing. For example, the plug-in might store preferences information in every document for its own use. You can set these warnings to use ClassID (when the plug-in creates new bosses) or ImplementationID (when the plug-in adds interfaces to existing bosses) values as triggers. Use kImplementationIDSpace to specify a list of ImplementationID values, and kClassIDSpace for ClassID values. You can put any number of IDs in the list, but all the IDs must be of the same type. Use a second resource to mark IDs of another type. Example 3 and Example 4 set the warning level to ignore data stored by the PersistentList plug-in in the SDK by adding two resources to PstLst.fr: EXAMPLE 3 Marking implementation IDs as ignored resource IgnoreTags(1) { kImplementationIDSpace, { kPstLstDataPersistImpl, kPstLstUIDListImpl, } }; EXAMPLE 4 Marking boss classes as ignored resource IgnoreTags(2) { kClassIDSpace, { kPstLstDataBoss, } }; You do not need to mark any IDs that do not appear in the document (for example, data that was written out to saved data) or implementations that are not persistent. You do not need to mark IDs if you want the default behavior. Persistent Data and Data Conversion 37 Persistent Data and Data Conversion Missing plug-ins Missing plug-in alert This alert is activated when a document is opened and contains data from one or more missing plug-ins that cannot be ignored. The document contains a list of the plug-ins that added data to it. Each piece of data added has an importance attached to it; this may be critical, default, or ignorable. Data marked as ignorable does not cause the alert to be activated. Data marked as critical or default causes the alert to be activated. In the case of critical data, the alert works more strongly; this is the only difference between critical and default data. The alert tells the user data is missing, presents a list of missing plug-ins, and allows the user to continue or cancel the open operation. Each missing plug-in has the chance to add a string to the alert that specifies additional useful information (e.g., a URL for purchasing or downloading the plug-in). The alert is modeled on the missing-font alert. The “Don’t Warn Again For These Plug-ins” option is de-selected by default. If this option is selected, the alert is not activated the next time a document is opened and any subset of the listed plug-ins is missing (and no other plug-ins are missing). This allows users accustomed to seeing (and ignoring) alerts concerning specific plug-ins to automatically bypass the alert, while still getting warned about data from any plug-ins newly found to be missing. The alert is activated again if a document is opened that uses other missing plug-ins. The alert is activated again if the “Don’t Warn Again For These Plug-ins” option is de-selected. Guidelines for handling a missing plug-in If a plug-in creates persistent data in a document, these guidelines ensure the document behaves gracefully if a user tries to open it when the plug-in is missing or if the document is edited by a user who did not have the plug-in: If your plug-in does not store data in documents, you do not need to take any special precautions. If the data stored by your plug-in does not reference other data in the document and does not appear visually in the document, mark the data as ignorable. If editing the document without your plug-in could corrupt the document, mark the data as critical. You can specify a string that is displayed when the plug-in is missing and the user opens a document that contains data added by the plug-in. See the ExtraPluginInfo resource, which may provide information like the URL of a site from which the missing plug-in can be obtained. See an example of the use of this resource in <SDK>/source/sdksamples/transparencyeffect/TranFx.fr. If there are checks your plug-in can do to restore the data’s integrity on opening a document edited without the plug-in, supply a FixUpData method. For an example, see <SDK>/source/sdksamples/persistentlist/PstLstPlugIn.cpp. If you want your plug-in to handle the storage of its own data, use the application-supplied mechanism that treats the plug-in’s data like a black box. (See “Black-box data storage” on page 39.) 38 Persistent Data and Data Conversion Missing plug-ins Data handling for missing plug-ins If a document contains data placed there by a plug-in that is not available, the user can choose to open the document anyway. If the data is completely self-contained, there may be no problem; however, if the plug-in’s data depends on anything else in the document, undesirable things can happen. Missing data not copied InDesign maintains most data in a centrally managed model in which the core-content manager keeps track of what information is added to the document, handles conversion of the data, and provides a convenient mechanism for instantiating objects based on the data. This approach does not allow the data to be copied when the plug-in is missing, however, because the content manager would not be able to provide these services for the missing plug-in’s copied data, and that potentially can leave the document in an invalid state. With the exception of those objects that hold onto only ClassID values, InDesign blocks copying data associated with missing plug-ins. This means no attribute is copied if the plug-in that supplies the attribute is missing. This applies to all attributes: text, graphics, table, cjk, etc. Furthermore, if a plug-in attached a data interface to an existing attribute, and the plug-in is missing, the attribute is copied but the addin data interface is not. This is consistent with how InDesign handles UID-based objects. Likewise, if a data interface is added to an XML element, the data interface is not copied if the plug-in that supplied it is missing. There are several features based on an object from a required plug-in holding a ClassID from an optional plug-in, including adornments, text composer, pair-kern algorithm, section numbers, and unit defaults. In these cases, the consequences of losing track of the plug-in that supplied the data is much less severe. Conversion of these ClassIDs is quite unusual and could be handled if necessary by issuing new ClassIDs. Error handling in the user interface when the plug-in is missing is much more graceful. Black-box data storage A second, simpler data-model storage mechanism was added for software developers requiring that data (like text attributes) is copied with the text, and for developers who want to attach data to other ID objects, such that it gets copied even when the source plug-in is missing. This mechanism is black-box data storage. In the simplest case, the black box is just a new persistent interface that sits on the object. A plug-in can store data in the box or fetch data out of the box. The data is keyed by a ClassID, which is supplied by the plug-in. Multiple plug-ins can store their data in the same black box, and each plug-in gets its own, unique, streamed access to its data. The black box just keeps track of the key, the length of the data, and the data stream. The software developer is responsible for handling everything else—conversion, swapping, etc. Users do not get a missing plug-in alert for data placed in a black box. Any UID-based object could have a black box. In addition, attributes and small bosses (used for XML elements) also can have black boxes. Persistent Data and Data Conversion 39 Persistent Data and Data Conversion Conversion of persistent data The following objects support black boxes: z kDocBoss — The root object of the document does not get copied. z kPageItemBoss — This includes all page item objects, including spreads, master pages, splines, frames, images, and text frames. z Attributes — This includes text, graphic, table, cjk, etc. (i.e., everything that appears in an AttributeBossList). For more information on the black-box mechanism, see IBlackBoxCommands, IBlackBoxCmdData, and IBlackBoxData in the API reference documentation. FixUpData Suppose a hyperlink attribute is linked to another frame, and the user can double-click the link to go to the frame. A plug-in supplies an observer, so if the frame is deleted, the link is severed. Now suppose you give the document containing the hyperlinks to someone who does not have the hyperlink plug-in. This person edits the document, deletes the frame, saves the document, then returns the document to you. The document is now corrupted, because your plug-in was unable to delete the associated link, which now points to an undefined frame. To restore the integrity of a document in this case, the plug-in can override the IPlugIn::FixUpData method. This method is called when the document is opened, if the plug-in was used to store data in the document and the document was edited and saved without the plug-in. In this case, the hyperlinks plug-in could override FixUpData to scan all its objects, checking whether the linked frame UIDs were deleted; when the document is opened with the plug-in, the method correctly severs the links. Conversion of persistent data This section describes types of conversion providers and the advantages of each type. Converting persistent data from an old document to a new one is complex, because each plugin can store data independently in the document. When the host opens a document created with an older version of the application or an older version of any plug-in used in the document, you must convert and update the older data to match the new format. Versioning persistent data is the process of converting persistent data in a database from one format to another. The data in different formats usually resides in different databases; for example, data in a database (document) from a previous version of InDesign versus that in a database (document) from a newer version of InDesign. Just as each plug-in having a persistent data implementation is responsible for the order of reading and writing its own data (thus implicitly defining a data format), each plug-in also is responsible for converting its own data from one format to another. Whether data in a database requires conversion usually is determined when the database is opened. 40 Persistent Data and Data Conversion Conversion of persistent data There are two approaches to converting persistent data: z You can use the host’s conversion manager to manage the conversion process. This approach is the most common. See “Converting data with the conversion manager” on page 42. z The plug-in that owns the data can manage when and how data is converted, using version information or other data embedded with the object data. See “Converting data without the conversion manager” on page 52. When to convert persistent data As a plug-in developer, you want to ensure your users can open documents with persistent data from an older version of your plug-in. To do this, your plug-in must provide data conversion function. The best time to consider your data-conversion strategy is when you realize your plug-in will store some data to a database. You need to implement data-conversion utilities in the following cases: z You change the order of IPMStream::Xfer* calls in the ReadWrite method. z You change a persistent object’s definition. z You re-number (change the value of) an ImplementationID or ClassID identifier. z You remove a plug-in and data from the removed plug-in might be in a document a user wants to open. In any of these cases, the conversion manager needs to be notified how to convert the persistent data for use by the loaded plug-in. Specifying how the persistent data format changed is somewhat different from adding persistent data to or removing it from a document. Besides telling the conversion manager to add or delete any obsolete data, the conversion provider has to be able to tell the conversion manager about every implementation in the plug-in that was ever removed, to keep the content manager up to date about the various persistent data formats. NOTE: To provide a document for use with an earlier version of InDesign, use the InDesign Interchange file format. At the very least, the resources required to support data conversion can help you keep a log of how your persistent data format has changed. Such a log can be useful. Sample conversion scenario Consider a plug-in with two released versions, 1 and 2, which use the same data format; in this case, both versions of the plug-in have the same format version number, 1. The new release of the plug-in, version 3, stores additional data, such as a time stamp. You must update the format version number to match the current plug-in version number; so, for plug-in version 3, the format version also would be 3. Because you changed the format version number, you must create a converter that converts from version 1 to version 3. See Table 1. Persistent Data and Data Conversion 41 Persistent Data and Data Conversion Conversion of persistent data TABLE 1 Version changes example Plug-in version Format change Format version 1 N/A (new plug-in) 1.0 2 No 1.1 3 Yes 3 4 Yes 4 For a fourth version of the plug-in, you again change the format, allowing a date stamp to be signed. Change the plug-in and format version numbers to 4, and add an additional converter to convert from version 3 to version 4. Conversions from version 1 to version 4 are done by the conversion manager, which chains the converters together; the first converts from format version 1 to format version 3, and the second converts from format version 3 to format version 4). Converting data with the conversion manager Each document contains header information about the content, which includes a list of all plug-ins that wrote data to the document and the version number of the plug-in last used to write that data. When a document is opened, the application checks whether any plug-ins are missing or out of date. If a plug-in is missing, it might provide an alert embedded in the document. (See “Missing plug-ins” on page 36.) If a plug-in is out of date, data written by the old plug-in must be updated to match the format required by the loaded plug-in. A plug-in can register a conversion service to do the update. The InDesign conversion manager (IConversionMgr) determines which conversions are required for opening the document and calls the appropriate plug-in to do the conversion. When the persistent data for any plug-in changes, this is a document format change. Any of the following can change the document format: 42 z Changes to the ReadWrite method — If the ReadWrite method is used to stream data to the document, changing the ReadWrite method might change the document format; however, an implementation might have a ReadWrite method that works with some other database or other data source, not with the document itself. For example, a widget has a ReadWrite method used for streaming to and from resources and to and from the SavedData file. Changes to a method that does not work with the document database do not require any special conversion. z Changes to an object’s definition — If you add an implementation to (or remove an implementation from) the definition of a persistent boss in the framework resource (.fr) file, you change how the object is streamed. If you add a new implementation, an old version of the object will stream, but it will not contain the data normally appearing for the implementation you added. This is fine if the data can be initialized adequately from the implementation’s constructor; otherwise, you may need to add a converter. If you change the implementation of an interface from one ImplementationID to another, you must convert the data. If you remove an ImplementationID from a class, you should add a converter to Persistent Data and Data Conversion Conversion of persistent data strip the old data from the object; otherwise, the obsolete data is carried around with the object indefinitely. z Re-numbering an ImplementationID or ClassID — If an ImplementationID or ClassID changes, you must register a converter so occurrences of the ImplementationID or ClassID in old documents can be updated. In practice, re-numbering a ClassID or ImplementationID is a source of many bugs and typically leads to corrupt documents, so we strongly recommend you not re-number an ImplementationID or ClassID. When you make a format change, you must do two things to maintain backward compatibility: z Update the version number of the plug-in whose data format you changed. z Provide a converter that can convert between the previous format and the new format. Updating version numbers Each plug-in has a plug-in version resource of type PluginVersion. The PluginVersion resource appears in the boss definition file. The first entry of this resource describes the application's build number; on the release build, this entry is the final-release version number. The second entry of the resource is the plug-in's ID, followed by three sets of version numbers, followed by an array of feature-set IDs. If any of the IDs in this list matches the current feature-set ID, the plug-in is loaded. To see an example, open any example .fr file in the SDK. Each version number has a major number and a minor number. The first version number is the version of the plug-in, which gets updated for every release of the plug-in. The second version number is the version of the application with which the plug-in expects to run. This ensures the user does not drop a plug-in compiled for one version of the application into an installation of another version of the application. The last number is the format version number, which indicates the version of the plug-in that last changed the file format; this is the version number written into the document, and it is the number the conversion manager checks to see whether conversion is required. The format version number does not always match the plug-in’s version number. The format version number does not generally change as often as the plug-in version number. The plug-in version number changes for every release of a plug-in, but the format version number changes only if the format for the data the plug-in stores in the document has changed and the conversion manager is required to convert the data. Adding a converter Converters can be implemented as conversion services. InDesign supports two types of service-provider-based data conversion: z Schema-based provider — Schema-based converters are configured through resources, are easier to use than code-based converters, and cover most format-change needs. Use this type of converter unless it cannot handle the special needs of your plug-in. z Code-based provider — If your implementation uses a special data-compression algorithm or other storage optimizations, involves data of variable length, or uses virtual object store (VOS) objects, schema-based converters cannot handle the necessary data format conversions. In this case, you must implement your own custom conversion provider. Persistent Data and Data Conversion 43 Persistent Data and Data Conversion Conversion of persistent data A conversion service is responsible for all conversions done by the plug-in. A converter might at first handle only a single conversion, from the first format to the second. Later, if you change the format again, you can add another conversion to the converter, to convert from the second format to the third. Suppose you market a plug-in that supplies a date stamp. You had released two versions (version 1.0 and version 2.0) of the plug-in without changing the persistent data created by the plug-in; so both releases have the same format version number (1.0). For the third released version of the plug-in, you add a time stamp. You must update the format version number to match the current plug-in version number; i.e., for plug-in version 3.0, the format version also must be 3.0. Suppose for the fourth released version of the plug-in (version 4.0), you again change the format, allowing a date stamp to be signed. You then change the format version number to 4.0 and add an additional converter, capable of converting from format version 3.0 to format version 4.0. Conversions from format version 1.0 to format version 4.0 can be done by the conversion manager, which chains the two converters together, using the first converter to convert from format version 1.0 to format version 3.0, and using the second converter to convert format version 3.0 to format version 4.0.) Adding a converter (either schema-based or code-based) to your plug-in means adding a new boss with two interfaces, IK2ServiceProvider and IConversionProvider. The IK2ServiceProvider implementation, kConversionServiceImpl, is provided by the application. You need to supply the IConversionProvider implementation. Here is a sample boss: /** This boss provides a conversion service to the conversion manager to use the schema-based implementation. */ Class { kMyConversionProviderBoss, kInvalidClass, { IID_ICONVERSIONPROVIDER, kMySchemaBasedConversionImpl, IID_IK2SERVICEPROVIDER, kConversionServiceImpl, } }, Most of the work is done in the conversion provider supplied with the SDK. The default implementation of IConversionMgr calls IConversionProvider::CountConversions and IConversionProvider::GetNthConversion to determine which conversions are supported by the converter. When you implement a new converter, CountConversions returns 1, and GetNthConversion returns fromVersion set to the version number before your change and toVersion set to the version number having your change in it. VersionID is a data type in the Public library; it consists of the PluginID value, the major format version number, and the minor format version number. For a new converter, fromVersion should be VersionID(yourPluginID, kOldPersistMajorVersionNumber, kOldPersistMinorVersionNumber). The toVersion should be the new format version number. 44 Persistent Data and Data Conversion Conversion of persistent data Your new conversion is added as conversion index 0. For a new converter, it looks like this: int32 TextConversionProvider::CountConversions() const { return 1; } void TextConversionProvider::GetNthConversion( int32 i, VersionID* fromVersion, VersionID* toVersion) const { *fromVersion = VersionID(kTextPluginID, kOldPersistMajorVersionNumber, kOldPersistMinorVersionNumber); *toVersion = VersionID(kTextPluginID, kNewPersistMajorVersionNumber, kNewPersistMinorVersionNumber); } When adding another change after a changed version already exists, the change numbers should chain together so the conversion manager can do changes across multiple formats. So, if your plug-in used three formats—starting with version 1, then changed in version 3, and changed again in version 4—your plug-in should register one converter that handles the conversion from format version 1 to format version 3 and another converter that handles the conversion from format version 3 to format version 4. If necessary, the conversion manager can chain them together to convert a document from version 1 to version 4. The methods would look like this: const int32 kFirstFormatVersion = 1; const int32 kSecondFormatVersion = 3; const int32 kThirdFormatVersion = 4; const int32 kFirstChange = 0; const int32 kNewChange = 1; int32 TextConversionProvider::CountConversions() const { return 2; } void TextConversionProvider::GetNthConversion( int32 i, VersionID* fromVersion, VersionID* toVersion) const { if (i == kFirstChange) { *fromVersion = VersionID(kTextPluginID, kMajorVersionNumber, kFirstPersistMinorVersionNumber); *toVersion = VersionID(kTextPluginID, kMajorVersionNumber, kSecondPersistMinorVersionNumber); } else if (i == kNewChange) { *fromVersion = VersionID(kTextPluginID, kMajorVersionNumber, kSecondPersistMinorVersionNumber); *toVersion = VersionID(kTextPluginID, kMajorVersionNumber, kThirdPersistMinorVersionNumber); } } Persistent Data and Data Conversion 45 Persistent Data and Data Conversion Conversion of persistent data Next, tell the conversion manager which information you changed. The default implementation of IConversionMgr calls IConversionProvider::ShouldConvertImplementation with each implementation in the document supplied by the plug-in. Depending on the data status of the implementation, the plug-in must return kMustConvert when the content must be modified, kMustRemove when the data is obsolete and must be removed, kMustStrip when the content must be stripped, or kNothingToConvert for all other cases. Using kTextFrameImpl as an example, define a method for IConversionProvider::ShouldConvertImplementation, returning kMustConvert when the tag is kTextFrameImpl and kNothingToConvert in all other cases. The plug-in should do this when the conversion manager is converting that plug-in’s data and not performing another conversion, so check the conversion index and make sure it is the one that you added. It might look like the following: IConversionProvider::ConversionStatus TextConversionProvider::ShouldConvertImplementation( ImplementationID tag, ClassID context, int32 conversionIndex) const { IConversionProvider::ConversionStatus status = IConversionProvider::kNothingToConvert; switch (conversionIndex) { case 0: if (tag == kTextFrameImpl) status = IConversionProvider::kMustConvert; break; default: break; } return status; } Next, implement ConvertTag to do the actual conversion. Suppose the TextFrame ReadWrite method writes an integer value and a real value, and you are adding a boolean. The ConvertTag implementation might look like the following, which illustrates what most converters look like: ImplementationID TextConversionProvider::ConvertTag( ImplementationID tag, ClassID forClass, int32 conversionIndex, int32 inLength, IPMStream* inStream, IPMStream* outStream, IterationStatus whichIteration) { ImplementationID outTag = tag; switch (conversionIndex) { case 0: if (tag == kTextFrameImpl) { if (inLength > 0) { int32 passThruInt; inStream->XferInt32(passThruInt); outStream->XferInt32(passThruInt); int32 passThruReal; inStream->XferInt32(passThruReal); outStream->XferInt32(passThruReal); // Adding new field bool16 smartQuotes = kTrue; outStream->XferInt32(smartQuotes); 46 Persistent Data and Data Conversion Conversion of persistent data } } break; default: break; } return outTag; } If the converter needs to convert a class, it implements ShouldConvertClass and ConvertClass. This is necessary only if the class is being deleted or is a container for some other data. (See “Containers and embedded data” on page 48.) Removing classes or implementations If you remove a ClassID or an ImplementationID from a version of your plug-in, the identifier also must be removed from documents as they are converted. The conversion manager removes an identifier for you if you implement your converter to return invalid status. For example, to remove a tag, implement ConvertTag as follows: ImplementationID TextConversionProvider::ConvertTag( ImplementationID tag, ClassID forClass, int32 conversionIndex, int32 inLength, IPMStream* inStream, IPMStream* outStream, IterationStatus whichIteration) { ImplementationID outTag = tag; switch (conversionIndex) { case 0: if (tag == kTagToRemove) outTag = kInvalidImpl; break; default: break; } return outTag; } Deleting a class is similar: implement ConvertClass to return kInvalidClass. Changing an implementation in one class Suppose a boss is defined with an IBoolData interface, implemented as kPersistBoolTrue, meaning it defaults to true. Suppose you change this to kPersistBoolFalse. When you read an old document with the new boss, you want it to use the new implementation. You would then write a converter to take the data stored as kPersistBoolTrue and switch it to be stored as kPersistBoolFalse. When you first access the boss, it has the old value. If you do not make a converter, the boss will not read the old data, because there is no interface in the new boss using the kPersistBoolTrue ImplementationID. Instead, the boss looks for kPersistBoolFalse but does not find it, because the old boss did not have it; therefore, the value is false, because it is the default value instead of the old value. To change the ImplementationID of the data in the document, make a conversion method to catch the old ImplementationID and change it to the new one. Do this only for your boss; do not change other bosses using kPersistBoolTrue. Your method might look like this: Persistent Data and Data Conversion 47 Persistent Data and Data Conversion Conversion of persistent data ImplementationID TextConversionProvider::ConvertTag( ImplementationID tag, ClassID forClass, int32 conversionIndex, int32 inLength, IPMStream* inStream, IPMStream* outStream, IterationStatus whichIteration) { ImplementationID outTag = tag; switch (conversionIndex) { case 0: if (tag == kPersistBoolTrue && forClass == kMyBoss) outTag = kPersistBoolFalse; bool16 theBool; inStream->XferBool(theBool); outStream->XferBool(theBool); break; default: break; } return outTag; } forClass is the boss in which the data was found. The conversion should be done only if forClass is the one you want changed. Also implement ShouldConvertImplementation. forClass is either the class in which the data was found or kInvalidClass if any class should match. The implementation of ShouldConvertImplementation looks like this: IConversionProvider::ConversionStatus TextConversionProvider::ShouldConvertImplementation ( ImplementationID tag, ClassID forClass, int32 conversionIndex) const { IConversionProvider::ConversionStatus status = IConversionProvider::kNothingToConvert; switch (conversionIndex){ case 0: if (tag == kTextFrameImpl && (forClass == kMyBoss || forClass == kInvalidClass)) status = IConversionProvider::kMustConvert; break; default: break; } return status; } Containers and embedded data InDesign does not have many instances of containers. One example is in the text attribute code. A text style is a UID-based boss object containing an implementation, TextAttributeList, that contains a list of attribute bosses (Bold, Point Size, Leading, and so on). These attribute bosses are not UID-based bosses; instead, TextAttributeList streams the ClassID for a boss, followed by the boss’s data, then streams the next boss in the list. TextAttributeList, therefore, must call the stream’s content tracker to notify the content manager that a new class was added to the document. 48 Persistent Data and Data Conversion Conversion of persistent data The following example illustrates why this is important. Suppose a new Red-Line plug-in adds an attribute to the style and the text does not compose correctly if the Red-Line plug-in is removed. Red-Line can list the attribute as critical, so the host provides a strongly worded warning when the user tries to open the document without the Red-Line plug-in. However, if TextAttributeList does not register the attribute boss with the content manager, the application never knows the attribute is in the document and cannot warn the user. Suppose the Red-Line plug-in is updated, and the attribute boss in particular is updated to store its data differently. The Red-Line plug-in registers a converter handling the format change. If the host does not know the attribute appears in the document, the Red-Line converter is never called to perform the conversion. The document appears to open correctly, but it crashes on the attribute’s ReadWrite method the first time the style is read. For the Red-Line attribute to be converted, TextAttributeList must register a converter. If the content manager was notified when the attribute was streamed, the conversion manager knows the attribute needs to be converted. It even knows the attribute was streamed by TextAttributeList. But the conversion manager has no way of knowing where the attribute is inside the data streamed by TextAttributeList; therefore, TextAttributeList should register a converter that calls back to the conversion manager to convert each piece of embedded data. Otherwise, the embedded data is not converted. Content manager The host has a content manager that tracks what data is stored in the document, which plug-in stored it, and the format version number of the plug-in last used to write the data. Think of this as a table attached to the root of the document: every ImplementationID part of the document appears in the table. This table also includes all ClassID values in the document. Table 2 and Table 3 are an example. TABLE 2 Version information ImplementationID PluginID Format version number (only minor number) kSpreadImpl kSpreadPluginID 0 kSpreadLayerImpl kLayerPluginID 0 kTextAttrAlignJustImpl kTextAttrPluginID 1 kCMSProfileListImpl kColorMgmtPluginID 3 ... Persistent Data and Data Conversion 49 Persistent Data and Data Conversion Conversion of persistent data TABLE 3 Class IDs in the document ClassID Plug-in ID Format version number (only minor number) kSpreadBoss kSpreadPluginID 1 kSpreadLayerBoss kLayerPluginID 1 kTextAttrAlignBodyBoss kTextAttrPluginID 3 kDocBoss kDocFrameworkPluginID 1 When an object is streamed to a document, the document receives the ClassID of the object and the data streamed by each of the object’s ReadWrite methods. The data written by a ReadWrite method is marked with the ImplementationID of the ReadWrite implementation; this way, when the data is read later, the system knows which C++ class to instantiate to read the data. IContentMgr maintains an overall list of the ClassID and ImplementationID values used in the document. When a new ClassID or ImplementationID is added to the document, IContentMgr checks which plug-in supplied the ClassID or ImplementationID, notes the plug-in ID and the format version number, and adds the new entry to the table. The plug-in supplying a ClassID is the one supplying the class definition. Only the plug-in supplying the original class definitions is considered; add-in classes do not count. The plug-in supplying an ImplementationID is the one that registered a factory for the ImplementationID. This data is used to detect missing plug-ins and manage document conversion. When the user opens a document containing data supplied by a missing plug-in, the host alerts the user that the document contains data from a missing plug-in. The host detects missing plug-ins by looking in the content manager to see which plug-ins supplied data to the document and checking this list against the list of loaded plug-ins to see whether any are missing. This data also is used for document conversion. When the user opens a document, the default implementation of IConversionMgr checks the format version number of the plug-ins supplying data to the document and compares it with the format version number of loaded plug-ins. Any mismatch means a conversion is required before the document can be opened. If there is a format version change without a supplied data converter, the document will not open. Conversion manager When a document is opened, the conversion manager is called to check whether any data in the document requires conversion. If the data requires conversion and a converter is available, the document is converted and opens as an untitled document. If a converter cannot be found, the host displays an alert message that warns the user the document cannot be opened because it cannot be converted. This initial check, implemented in IConversionMgr::GetStatus, happens very early in the process of trying to open the document, before any objects in the document are accessed (i.e., before any of their ReadWrite methods are called). This is critical, because a ReadWrite method will not succeed if the object needs to be converted. The conversion manager accesses the content manager (converting it if necessary), and uses the content manager to find out what 50 Persistent Data and Data Conversion Conversion of persistent data plug-ins supplied data to the document. If any plug-ins used in the document have different formats than the formats of the loaded plug-ins, conversion is necessary. Next, the conversion manager sees whether there is a converter to convert from the format in the document to the format associated with the loaded plug-in. If such a converter is available, conversion is possible; the document may be closed and opened again as an untitled document. If the GetStatus method returns with a result indicating conversion is not necessary, the open operation proceeds without calling the conversion manager again. If the GetStatus method returns with a result indicating conversion is necessary but impossible, the open operation is aborted. If the GetStatus method returns with a result indicating conversion is required and a converter is available, the conversion manager’s ConvertDocument method is called to perform the conversion. The first thing ConvertDocument does is compile a list of the classes and implementations in the document that must be converted. A plug-in may have many different implementations that wrote data to the document, but only one of these implementations might require conversion. The conversion manager uses the content manager to iterate over classes and implementations supplied by the plug-in, and the conversion manager calls the converter to find out which classes and implementations require conversion. Each class or implementation in the document that the converter says must be converted is added to the list of classes or list of implementations to be converted. Other data written by the plug-in is ignored by the converter; it is not converted. The next step is to iterate over the UIDs in the document. For each UID, the conversion manager gets the class of the UID. If the class is on the list of classes to be converted, the conversion manager calls a converter for the class. If, as is more common, the class contains an implementation needing to be converted, the conversion manager opens an input stream on the UID and iterates through the implementations in the UID. If any implementation in the UID requires conversion, an output stream is opened on the UID. Any implementation not requiring conversion is copied to the output stream. If an implementation requires conversion, its converter is called. The converter gets passed the input stream and the output stream. The converter reads from the input stream in the old format and writes to the output stream in the new format. After the UID iteration is completed, the content manager is called to update the format numbers for all plug-ins that were outdated, to show their data was converted and is up to date. After this, it is safe for ReadWrite methods to be called on objects in the document. If any converter requires access to another object to do its conversion, it is called in the last phase of conversion. For example, suppose there was one document-wide preference setting for whether text in frames has smart quotes turned on, but you want to make this a per-frame setting. The text frame must store a new flag that indicates whether smart quotes are on or off. The converter adds a new flag in the first phase of conversion, but the converter cannot set the correct value for the flag until the preferences are converted. So, the converter needs to be called once again, after the first phase is complete and it is safe to instantiate the preferences, to get the value of the document-wide smart-quotes setting so the converter can set the frame’s new smart-quotes setting accordingly. Persistent Data and Data Conversion 51 Persistent Data and Data Conversion Conversion of persistent data Converting data without the conversion manager To perform format conversion without the conversion manager, the persistent data itself must identify the version of the plug-in that originally wrote the information. To use this method, add a version number to the implementation classes, and implement the ReadWrite method to write the version number first whenever the method writes data, as shown in Figure 3. This method has the advantage of forward compatibility. FIGURE 3 Persistent data with version number k<Foo>Boss persistent data record ID Length Data Vers. | Other ID Length Data Vers. | Other For example, suppose the first version of your plug-in stores two-byte values, fOne and fTwo, and uses a byte value to store the data’s version number. The ReadWrite method for this implementation would be something like Example 5: EXAMPLE 5 ReadWrite method supporting multiple versions (version 1 of the plug-in) FooStuff::ReadWrite(IPMStream* stream, ImplementationID implementation) { stream->XferByte(0x01); stream->XferByte(fOne); stream->XferByte(fTwo); } The second version of this plug-in modifies the data format by adding a 16-bit integer value, fThree. In this version, your ReadWrite method must be able to read data in either format, but it always must write data back in the new format. See Example 6: EXAMPLE 6 ReadWrite method supporting multiple versions (version 2 of the plug-in) FooStuff::ReadWrite(IPMStream* stream, ImplementationID implementation) { uchar version = 0x02; //Always *write* version 2 data stream->XferByte(version); if (version == 0x01) { stream->XferByte(fOne); stream->XferByte(fTwo); } else { stream->XferByte(fOne); stream->XferByte(fTwo); stream->XferInt16(fThree); } } 52 Persistent Data and Data Conversion Resources This code both reads and writes all data for this implementation. It could check whether the stream is a reading or writing stream and perform only the needed operation, but the dual-purpose code actually is simpler and accomplishes the same thing. If the stream is a ReadStream, the version is initialized as 0x02 but immediately replaced by the contents of the first byte in the stream, and the rest of the stream is processed according to the version number found. If this plug-in encounters data claiming a version number greater than 2, only the data it understands (processed by the else clause) is read. This method allows the version 2 plug-in to work with data from both earlier and later versions. Each new version of the plug-in using this method must preserve the portion of the stream previous versions created and add new information only to the end. When using this approach, the plug-in’s data version number must not change between versions of the plug-in, but only when a data converter is being supplied to convert the data from one version to another. Resources This section explains the fundamental elements and ODFRez resources you need when incorporating a converter in your plug-in. PluginVersion resource, format numbers, and their macros PluginVersion is a resource included in every InDesign and InCopy plug-in. Part of the resource is the declaration of a persistent data format number, like the following: kSDKDefPersistMajorVersionNumber, kSDKDefPersistMinorVersionNumber, For an example, see the resource definition in <SDK>/source/sdksamples/basicdialog/BscDlg.fr. Each plug-in specifies a different format number. These format numbers are stored in documents, so when a document is opened, the content manager can determine whether data conversion is needed. This determination is made by comparing the format numbers stored in the document for each plug-in with the format numbers declared by loaded plug-ins. If the format numbers are different, the conversion manager is called upon to do a data conversion. Format number values must meet the following criteria: z Be greater than or equal to zero. z Increase with each format change. z Increment if the data format of any persistent class in a plug-in changes. NOTE: If multiple persistent classes in a plug-in change their data formats at the same time, the data-format version number needs to increment only once. How much you increment data format version numbers is up to you. Format-number values are just numbers; however, you might find it easier to use #define macros for format numbers instead of using their values directly. Persistent Data and Data Conversion 53 Persistent Data and Data Conversion Resources Table 4 lists format-number macros and their values from previous InDesign SDKs. See <SDK>/source/sdksamples/common/SDKDef.h. TABLE 4 Format number macros from prior InDesign SDKs Version Macro: Major Macro: Minor Tuple 1.0 kSDKDef_10_PersistMajorVersionNumber kSDKDef_10_PersistMinorVersionNumber {0, 307} 1.5 kSDKDef_15_PersistMajorVersionNumber kSDKDef_15_PersistMinorVersionNumber {1, 0} 1.0J kSDKDef_1J_PersistMajorVersionNumber kSDKDef_1J_PersistMinorVersionNumber {2, 1} 2.0 / 2.0J kSDKDef_20_PersistMajorVersionNumber kSDKDef_20_PersistMinorVersionNumber {4, 1} CS / CS Japanese (3.0 / 3.0J) kSDKDef_30_PersistMajorVersionNumber kSDKDef_30_PersistMinorVersionNumber {5, 1} Setting up resources With the first format change for a plug-in, you must add a converter (either schema-based or code-based) to your plug-in (only one converter per plug-in). See “Adding a converter” on page 43. Schemas The schema resource defines which formats of which implementations the converter should handle. The schema resource is defined in your .fr file and compiled using the ODFRC (Open Document Framework Resource Compiler). See Example 7 and <SDK>/public/includes/Schema.fh. EXAMPLE 7 Schema resource resource Schema(uniqueResourceID) { ImplementationID, { schemaFormatMajorNumber, schemaFormatMinorNumber }, { // [0..n] SchemaFields go here (see SchemaFields.fh) } }; Examples When you define a schema resource, you explicitly state which format number of which implementation it defines. It knows which plug-in contains the implementation, because it is defined implicitly to be the plug-in that contains the schema resource. In other words, all schemas defined in plug-in A are for implementations provided by plug-in A. The schema-based converter uses the information in this resource (or the SchemaList resource) to determine how to map persistent data from one format to another. 54 Persistent Data and Data Conversion Resources In Example 8, (1) identifies the schema resource ID. The value does not matter, as long as it is unique among all schema resources compiled into the plug-in. The first item in the schema specifies the implementation ID, and the second item specifies the format number as a tuple {1, 0}. Next comes the schema field list. Curly brackets ( { } ) delimit the list, and commas separate the individual fields. Each field has a type, name, and default value. It is extremely important each field name is unique and these values are not re-used when a field is deleted. Field names must be unique among the schemas that describe different formats of the same implementation, because this is what allows data mapping between different format numbers. NOTE: Although it is not done in the example below, we recommend you use #define macros for each field name, to enhance readability. EXAMPLE 8 Schema resource from <SDK>/sdksamples/snapshot/Snap.fr resource Schema(1) { kSnapPrefsDataPersistImpl, // ImplementationID {RezLong(1), RezLong(0)}, // format number { {PMString {0x0001, ""}}, // dialog default file name {ClassID {0x0002, 0}}, // format class ID, fFormatClassID {Real {0x0003, 1.0}}, // fScale {Real {0x0004, 72.0}}, // fResolution {Real {0x0005, 72.0}}, // fMinimumResolution {Real {0x0006, 0.0}}, // fBleed {Bool16 {0x0007, 0}}, // fDrawArea {Bool16 {0x0008, 0}}, // fFullResolutionGraphics {Bool16 {0x0009, 0}}, // fDrawGray {Bool16 {0x000a, 0}}, // fAddAlpha {Int32 {0x000b, 512}}, // fDrawingFlags, set default to IShape::kPrinting == 512 {Bool16 {0x000c, 0}}, // fIndexedColour } }; In Example 9 (based on the preceding Snap.fr example), there is a new schema resource ID (2). Inside the schema, the following changes occurred: z The implementation ID has not changed, but the format number is specified as a tuple {1, 1}. z schemaFormatMinorNumber changed from 0 to 1. z In the schema field list, the fifth field (0x0005, fMinimumResolution) was deleted. During conversion, the fifth field (Real) is stripped from the existing data. z The seventh field changed its type. It uses the same name but is now of type Bool8. This requires an implicit conversion. (For a table of valid and invalid type conversions, see the “Versioning Persistent Data” chapter of Adobe InDesign CS4 Solutions.) z A new field (0x000d, fMaximumResolution) was added. On conversion, an element of type Int32 (with a value of 3) is appended to the end of the existing data. Persistent Data and Data Conversion 55 Persistent Data and Data Conversion Resources EXAMPLE 9 Hypothetical schema resource resource Schema(2) { kSnapPrefsDataPersistImpl, // implementation ID {RezLong(1), RezLong(1)}, // format number { {PMString {0x0001, ""}}, // dialog default file name {ClassID {0x0002, 0}}, // format class ID, fFormatClassID {Real {0x0003, 1.0}}, // fScale {Real {0x0004, 72.0}}, // fResolution {Real {0x0006, 0.0}}, // fBleed {Bool8 {0x0007, 0}}, // fDrawArea {Bool16 {0x0008, 0}}, // fFullResolutionGraphics {Bool16 {0x0009, 0}}, // fDrawGray {Bool16 {0x000a, 0}}, // fAddAlpha {Int32 {0x000b, 512}}, // fDrawingFlags, set default IShape::kPrinting == 512 {Bool16 {0x000c, 0}}, // fIndexedColour {Int32 {0x000d, 3}}, // minimum resolution enum } }; Default values Default values in a schema are used only when the associated field is added to the data stream by conversion. For example, if an implementation originally contained only one int32 value but now also needs a bool16 value, the first schema lists only the int32 and the second schema lists both the int32 and the bool16. When the conversion runs, the schema converter writes a bool16 into the output stream, using the value specified as the default. Because the int32 already existed, the default value specified by the schema is not used. Suppose you have an implementation with two int32 values. In your constructor, you give them values of 11 and 52. The schema should reflect this. If you later decide 53 is a better default value for the second one, change the schema to match. In this case, however, you do not need a new schema. SchemaList The SchemaList resource allows you to specify several schemas in one resource, for convenience. Example 10 shows the two previous schema resources combined in one SchemaList. Even if initially you have only one Schema inside your SchemaList, it is a good idea to create this resource because, over the course of development, this SchemaList resource acts as a persistent data format log. 56 Persistent Data and Data Conversion Resources EXAMPLE 10 Hypothetical SchemaList resource resource SchemaList(uniqueResourceID) {{ Schema // schemaTypeIdentifier { kSnapPrefsDataPersistImpl, {RezLong(1), RezLong(0)}, { {PMString {0x0001, ""}}, {ClassID {0x0002, 0}}, {Real {0x0003, 1.0}}, {Real {0x0004, 72.0}}, {Real {0x0005, 72.0}}, {Real {0x0006, 0.0}}, {Bool16 {0x0007, 0}}, {Bool16 {0x0008, 0}}, {Bool16 {0x0009, 0}}, {Bool16 {0x000a, 0}}, {Int32 {0x000b, 512}}, {Bool16 {0x000c, 0}}, } }; Schema // schemaTypeIdentifier { kSnapPrefsDataPersistImpl, {RezLong(1), RezLong(1)}, { {PMString {0x0001, ""}}, {ClassID {0x0002, 0}}, {Real {0x0003, 1.0}}, {Real {0x0004, 72.0}}, {Real {0x0006, 0.0}}, {Bool8 {0x0007, 0}}, {Bool16 {0x0008, 0}}, {Bool16 {0x0009, 0}}, {Bool16 {0x000a, 0}}, {Int32 {0x000b, 512}}, {Bool16 {0x000c, 0}}, {Int32 {0x000d, 3}}, } }; }} The possible types for schemaTypeIdentifier (see Example 10) are listed below. See Schema.fh for their definitions. z ClassSchema — Schema for classes in the current plug-in. z OtherClassSchema — Like ClassSchema, but you can specify it for another plug-in by an additional PluginID field. z ImplementationSchema — Schema for implementations in the current plug-in. Persistent Data and Data Conversion 57 Persistent Data and Data Conversion Resources z Schema — Another name for ImplementationSchema, because this is the most common type. z OtherImplementationSchema — Like ImplementationSchema, but you can specify it for another plug-in by an additional PluginID field. DirectiveList To instruct the schema-based converter to add or remove implementations or an entire boss, specify a DirectiveList resource to your resource file, as shown in Example 11. (The DirectiveList resource formerly was known as BossDirective.) The DirectiveList resource is defined in your .fr file and compiled using ODFRC. EXAMPLE 11 DirectiveList syntax resource DirectiveList(uniqueResourceID) { { // [0..n] Directives go here } }; A DirectiveList resource is required each time you do any of the following: z Add a new boss or remove an existing one. z Add an implementation to a boss or remove one from a boss. z Change the ID of a boss or implementation. The DirectiveList resource serves several purposes: z Helps the conversion manager delete unnecessary data from a document when a boss or implementation is removed. z Keeps the content manager up to date regarding a document’s contents. z Allows the conversion manager to do its job correctly, even when a boss or implementation moves to a different plug-in. The possible list of directives is in Table 5. TABLE 5 Possible list of directives 58 Directive Description IgnorePlugin Mark a plug-in as ignorable. MoveClass Moves a boss class from one plug-in to another. MoveClassToPlugin A boss was moved from one plug-in to another. MoveImplementation Moves an implementation from one plug-in to another. MoveImplementationToPlugin An implementation was moved from one plug-in to another. RemoveAllImplementation Removes an implementation from all boss classes. RemoveAllOtherImplementation Removes an implementation from all boss classes. Persistent Data and Data Conversion Advanced schema topics Directive Description RemoveClass Removes a boss class from a plug-in. RemoveImplementation Removes an implementation from a boss class. RemoveOtherClass Removes a boss class from another plug-in. RemoveOtherImplementation Removes an implementation from a boss class. RemovePlugin Removes an entire plug-in. RenumberPlugin Re-numbers an entire plug-in. ReplaceAllImplementation Replaces one implementation with another in all plug-ins. ReplaceClass Replaces one boss class with another. ReplaceImplementation Replaces one implementation with another in a specific plug-in. NOTE: See Schema.fh. Fields vary by type of directive. Advanced schema topics Arrays of values Suppose an implementation contains three boolean flags followed by four uint32 values. The schema could contain seven separate fields, or it could define two array fields, as in Example 12: EXAMPLE 12 Schema resource with array fields #define kBarOptions 1 #define kBarValues 2 resource Schema(2) { kBarImpl, {1, 0}, { {Bool16Array{kBarOptions, {kTrue, kFalse, kTrue}}}, {Uint32Array{kBarValues, {0, 0, 0, 0}}} } }; The number of default values statically determines the number of elements in each array. Note that the set of default values is enclosed in braces. Persistent Data and Data Conversion 59 Persistent Data and Data Conversion Advanced schema topics FieldArray If the quantity of array elements is dynamic or an array consists of structures rather than single elements, use a FieldArray, which is a type of field, like Bool16, Uint32Array, or any of the other types in Schema.fh. In the following example, the Bar implementation differs slightly from the previous example. Instead of having three flags followed by four values, it has a value associated with each flag, and the number of (flag, value) pairs is dynamic: EXAMPLE 13 #define kBarPairs 1 #define kBarOption 2 #define kBarValue 3 resource Schema(3) { kBarImpl, {1, 0}, { {FieldArray{kBarPairs, {Uint16{0}}, {{Bool16{kBarOption, kFalse}}, {Uint32{kBarValue, 0}}}}} } }; The syntax looks slightly complicated because of ODFRC limitations, but it is fairly straightforward. The schema contains only one field; its type is FieldArray, and its name is kBarPairs. Following the field's name is its iteration count. Because this is an attribute of the FieldArray, it has a type but not a name. It also has a default value, which usually is zero. The counter might be a signed or unsigned integer that is 8, 16, or 32 bits wide. NOTE: The iteration count immediately precedes the iterated values. (If your implementation's persistent data requires the count be elsewhere, you must write your own conversion provider.) Following the iteration count is the list of iterated fields. Each has a type, name, and default value, like any other field. The default value is not used unless the iteration count has a nonzero default. In the preceding example, the output stream would simply be “0.” If the default iteration count were 2, the output would be “2, kFalse, 0, kFalse, 0.” FieldArrays can be nested up to three levels deep. Conditional-field inclusion An important variant of the FieldArray type is the FieldIf type. Use this construct to include a block of fields zero times if a condition is not met or once if the condition is met. The conditional value can be of type Bool8, Bool16, ClassID, or ImplementationID. If the conditional value is of type ClassID or ImplementationID, the fields are included if the ID is valid. 60 Persistent Data and Data Conversion Advanced schema topics Example 14 is a slight variant of Example 13: EXAMPLE 14 resource Schema(4) { kBarImpl, {1, 0}, { {FieldIf{kBarPairs, {Bool16{kFalse}}, {{Bool16{kBarOption, kFalse}}, {Uint32{kBarValue, 0}}}}} } }; In this case, kBarOption and kBarValue are included zero or one times, depending on the Bool16 value. FieldIf constructs can be nested up to three levels deep. Persistent Data and Data Conversion 61 Persistent Data and Data Conversion Advanced schema topics 62 Commands Concepts Commands This chapter describes InDesign’s command architecture. It also outlines how to find and use the commands provided by the InDesign API, how to implement new commands of your own, and other extension patterns associated with commands. Concepts This section introduces the generic command pattern, databases that provide persistence to the application’s objects, and models that represent the application’s objects in memory. Command pattern The intent of the command pattern is as follows: “Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests and support undoable operations.” (This is described in Gamma, Helm, Johnson, and Vlissides, Design Patterns, Addison-Wesley, 1995.) The structure of this pattern is shown in Figure 4. FIGURE 4 Client Command Pattern Structure Invoker Command + Execute() : void Receiver + Action() : void ConcreteCommand + Execute() : void receiver->Action(); This pattern decouples the object that invokes an operation from the object that implements it. The client wants an operation to be performed, the receiver knows how to perform the operation, and the two are decoupled by this pattern. The command declares an interface for executing an operation. The client does not send messages directly to the receiver; rather, the client creates a concrete command object and sets its receiver. The concrete command implements execute by calling the corresponding operation on the receiver. The invoker asks the command to carry out the request, which causes the receiver to perform the operation. Within the InDesign API, an implementation of the command pattern is used in situations where preventing data corruption is paramount and users must be able to undo or redo changes. See “Commands” on page 68. Commands 63 Commands Concepts Databases and undoability A persistent object has its state maintained outside the application runtime. It can be removed from main memory and returned again, unchanged. The application maintains persistent objects in a database. A database on disk is an opaque binary file in the operating system’s file system. This database file stores the serialized state of a collection of objects. The set of objects stored in a particular database is collectively known as a model. For example, an InDesign document file like Untitled-1.indd is a database file that represents the state of an instance of a document model. See “Models” on page 64. Objects are stored in a database in the following format: z Objects that persist are stored as a tree of objects, each of which is associated with and persisted by a database. z Each persistent object has a identifier, the UID, that identifies it uniquely within its database. z Each persistent object (except the root object) is owned and referred to by another object, the parent. A persistent object also can be referenced by other objects, though this does not indicate any form of ownership. The class that represents a database is IDataBase. For more detail, see the “Persistent Data and Data Conversion” chapter. Databases must be consistent and stable. Some databases also need to support undoability—the ability for a user to undo or redo changes. For example, the ability to undo changes made to a document is required; however, there is no requirement to undo changes made to the database that persists the user interface state. Table 6 shows the databases that exist and their support for undoability. If a database supports undoability, that support cannot be turned off. All changes to objects that persist in the database must be undo-able. Turning off undo support is not allowed, because it would disable error handling and increase the risk of document corruption. NOTE: To change objects that persist in a database that supports undo, we recommend using commands. If, however, you need to change data without showing something in the Edit > Undo menu, you can bypass commands and wrap your changes in calls to CmdUtils::BeginAutoUndoSequence and CmdUtils::EndAutoUndoSequence. Models A model is a collection of objects backed by a database for persistent storage. A model is a treestructured graph of objects. The ownership relationships between objects in a model defines this tree structure. Ownership relationships are just parent-child relationships within the tree. 64 Commands Concepts Document model Documents are represented by the document model. Figure 5 shows an example. FIGURE 5 Objects in a document model (instance diagram) Document content such as layout and text. UID 60 :kSpreadBoss UID 1 :kDocBoss ISpreadList IStoryList ISpread UID 41 : kTextStoryBoss Document preference settings such as styles and swatches. IDocument IDocument::GetDocWorkSpace ITextModel UID 75 : IWorkspace kDocWorkspaceBoss IStyleGroupManager UID 125 :kStyleBoss IStyleInfo ISwatchList UID 91 : kPMColorBoss IColorData ITextAttributes The document (kDocBoss) is the root object in the document model. It owns a collection of spreads (kSpreadBoss), stories (kTextStoryBoss), a workspace (kDocWorkspaceBoss), and so on. These objects may own further objects specific to their domain. The document’s workspace owns objects like styles and swatches, which can be used throughout the document. The database file that provides persistence for a document model is an end-user document file; for example, a file Untitled-1.indd saved from InDesign. Commands 65 Commands Concepts Defaults model Global preference settings are represented by the defaults model. Figure 6 shows an example. FIGURE 6 Objects in the defaults model (instance diagram) Global default preference settings such as styles and swatches. UID 1 : kWorkspaceBoss IStyleGroupManager UID 27 :kStyleBoss IStyleInfo IWorkspace ISwatchList UID 42 : kPMColorBoss IColorData ITextAttributes The workspace (kWorkspaceBoss) is the root object in a defaults model. It owns the objects that represent default preference settings like styles, swatches and so on. The defaults model is global and is accessed from the session (kSessionBoss) via the ISession interface. When a new document is created, preference settings can be copied from the defaults model into the document’s workspace (kDocWorkspaceBoss). The database file that provides persistence for this model is an application defaults file. For example, the file named InDesign Defaults is the database file used by InDesign to persist the defaults model. 66 Commands Concepts Session model A session of an application is represented by the session model. Figure 7 shows an example. FIGURE 7 Objects in the session model (instance diagram) UID 1 :kSessionBoss ISession UID 2 :kAppBoss IApplication UID 3 : kActionManagerBoss UID 4 : kPanelManagerBoss UID 5 : kToolManagerBoss UID 6 : kDocumentListBoss The session (kSessionBoss) is the root object in the session model. This model owns application-related objects that must persist from session to session. For instance, user interface objects are found here, together with other objects that store the application’s type system (the boss classes provided by all registered plug-ins). The database file that persists objects in this model is the application’s saved data file. For example, the file named InDesign SavedData is the database file used by InDesign to persist the session model. NOTE: Objects in the session model can be modified by calling mutator methods on their interfaces directly. There is no need to modify them using commands. The database that persists this model does not support undo. Books, asset libraries, and other models Several other features in an application have their own dedicated model, together with a database that provides that model with persistence. Prominent examples are books, asset libraries, and the scrap. See Table 6 for the level of undo support provided by their databases. Commands 67 Commands Commands Commands This section describes how commands are used in the application. It includes sections on the CmdUtils class, which is fundamental to the processing of commands, and how to use command sequences to group multiple commands into one logical unit. Within the application, the most prevalent use of commands by client code is to modify persistent objects in the document model or defaults model. For example, plug-ins use commands to create frames in a document or modify the default text style. Commands encapsulate the changes made to persistent objects into a database transaction. Encapsulating changes in this way helps prevent corruption. Furthermore, any change to the state of persistent objects that needs to support undo must be made using a command. Commands change persistent objects by doing the following: z Calling mutator methods on interfaces that exist on persistent objects. z Processing other commands (that call mutator methods on interfaces that exist on persistent objects). z Calling utilities that process commands (that call mutator methods on interfaces that exist on persistent objects). z A mixture of the above. A command is processed by the application; this means an instance of the command is passed to the application to be executed. A command can change persistent data within only one database each time it is processed. The processing of a command moves the database from one consistent state to another. When a command is used to modify objects that persist in a database that supports undo, that command can manifest on the undo and redo menu items, and the database automatically reverts the state of affected objects on undo and restore the changed state on redo. NOTE: Before InDesign CS4, commands were directly responsible for reverting or restoring the changes they made to persistent objects on undo and redo. The application has taken over this responsibility. The InDesign API provides commands for plug-ins to use. See “Command processing and the CmdUtils class” on page 70 and “Key client APIs” on page 84. Plug-ins also can introduce new commands using the command extension pattern. See “Command” on page 86. This is required when a plug-in adds custom persistent data to a document, defaults, or other objects that persist in a database that supports undo. The extension patterns named persistent interface and persistent boss are ways in which custom persistent data can be added to a database. See “Persistent interface” on page 89 and “Persistent boss” on page 91. 68 Commands Commands Command parameters Commands implement the protocol used to modify objects that persist in a database that supports undo. A client initiates this protocol by instantiating a command and passing it off to the application for processing. The client also is responsible for initializing the state of the command, including the setting of parameters. In general, the command pattern supports two mechanisms for parameter passing: 1. The UIDList in the ICommand interface (the “item list”), which identifies a set of persistent objects; see ICommand::SetItemList. On input, this might identify the set of page items on which the command operates. For example, a page item move command (kMoveAbsoluteCmdBoss) would use this to identify the set of items to be moved. On output, the item list might identify the set of object manipulated by a command. For example, a page item create command (kNewPageItemCmdBoss) would provide the UIDs of the objects created as a result of the command being processed. The use of the command’s item list is specific to each command; a command is not required to use the item list. 2. Data-carrying interfaces on the command’s boss class. For example, the command used to apply a particular text style aggregates an IBoolData interface to define whether character styles should be overridden, and an IRangeData interface to indicate the range of text that should be updated by the command. These two approaches for passing parameters are shown in Figure 8. There is a command boss class showing two aggregated interfaces, ICommand and a data-carrying interface (ISomeData). Parameters can be passed through the item list in ICommand, the data-carrying interface, or both. FIGURE 8 Passing parameters to commands «boss» kSomeCommandBoss «interface» ICommand + GetItemList() : const UIDList* + SetItemList(const UIDList&) : void Commands «interface» ISomeData + GetData() + SetData() 69 Commands Commands Command undoability Each command has a property called undoability (see ICommand::Undoability), which determines whether the command name can appear in undo and redo menu items (i.e., whether the changes made by the command can be undone or redone in a distinct step). z An undoability of kRegularUndo is used by commands whose changes need to appear as a separate named step in undo and redo menu items. This is the default behavior. z An undoability of kAutoUndo is used by commands whose changes do not appear as a separate named step; for example, commands whose changes should be undone or redone with an existing step. Changes made to objects that persist in a database that supports undo must be undoable. To achieve this, the various extension patterns involved, such as commands and persistent interfaces, must be implemented following the rules described in this chapter. The database then automatically reverts the state of affected objects on undo and restores the changed state on redo. The undoability of a command (kRegularUndo / kAutoUndo) has no effect on this behavior. It affects only whether the command appears as a distinct step in undo and redo menu items. Command processing and the CmdUtils class Client code uses commands when changing objects that persist state in any database that supports undo. For example, commands are used to change objects in the document model or the defaults model. The level of support for undo of each database is given in Table 6. To change the objects, client code creates instances of one or more commands and submits these instances to the application for execution. For example, to create frames in a document, a plug-in either creates commands to be processed and passes them to the application or calls a helper class that encapsulates both the creation and request for processing. The helper classes provided by the InDesign API are introduced in “Command facades and utilities” on page 84. Client code that must create commands uses the CmdUtils class. CmdUtils::CreateCommand creates an instance of a specific command. The client code parameterizes the command, using the command’s item list and data interfaces. The client code submits the command to the application for execution, by calling CmdUtils::ProcessCommand. Client code can group the commands it processes into command sequences, using methods and classes provided by CmdUtils. Guidance on processing commands and command sequences is in “Command-processing APIs” on page 86 and the “Commands” chapter of Adobe InDesign CS4 Solutions. The sequence of calls involved in processing a command is shown in Figure 9. The client code creates the command, populates the item list and other data interfaces, then passes the command off for processing. 70 Commands Commands FIGURE 9 Client code Client processing a command CmdUtils A Command A Persistent Interface CreateCommand Some client code creates an instance of a command using CmdUtils::CreateCommand construct SetItemList The client sets the command parameters, both through the item list (shown here) or through data carrying interfaces. ProcessCommand Do Set PreDirty The processing of the command is initiated through the client calling CmdUtils::ProcessCommand. Client code creates command, sets parameters and passes it for processing. The client should also test error state on return, before processing further commands. CmdUtils should be used for all client interactions with the commands sub-system. The rest of the internals are not shown in this diagram. The update to some interface on a (UID based) boss object. The call to PreDirty allows the application to track the changes made so that the application can undo or redo the changes automatically. Command sequences A command sequence (see ICommandSequence) groups a set of commands into a single undoable step that changes the model from one consistent state into another. The command sequence manifests on the undo and redo menu items as a single item. Commands 71 Commands Commands Command sequences can be nested. For example, say you begin a sequence in one method, then call a second method that begins a second sequence. The second sequence is said to be nested within the first. When sequences are nested, only one sequence—the outermost one— appears on undo and redo menu items. Command sequences assimilate all commands are processed within their scope, whether the command is processed directly from within the sequence or indirectly through subcommands (commands processed by a command). See the “Commands” chapter of Adobe InDesign CS4 Solutions for how to write code that uses command sequences. A typical scenario for a command sequence is shown in Figure 10. Between the BeginCommandSequence and EndCommandSequence calls, all commands processed act as a single set of changes; only one element will appear on undo and redo menu items. FIGURE 10 Calls made for a command sequence Client code CmdUtils BeginCommandSequence ICommandSequence*= SetName ICommandSequence The client creates a new command sequence. The client gives the sequence a name, otherwise the sequence uses the name of the first command processed. ProcessCommand ProcessCommand Multiple commands are processed within the scope of a sequence. EndCommandSequence The client indicates the sequence is complete. A command sequence can change persistent objects in more that one database. (A command, on the other hand, can change objects only in one database each time it is processed.) Operations that change objects in two or more documents can be implemented using a command sequence. Such a set of modifications manifests in undo and redo menu items for all affected documents. 72 Commands Command managers, databases, and undo support A command sequence has limited support for error handling: the sequence either succeeds entirely or fails. An abortable command sequence (see IAbortableCmdSeq) allows more sophisticated error handling, to allow for fail/retry semantics. Abortable command sequences incur a significant performance overhead and should be used only where absolutely necessary. Guidance on using these types of sequence is in the “Commands” chapter of Adobe InDesign CS4 Solutions. Command managers, databases, and undo support This section describes how command managers relate to the application’s databases. The application object model realizes a tree-structured graph of boss objects. Within this tree are several distinct models, notably the session model, the defaults model, and one or more document models (see “Models” on page 64). Each model has a distinct database that provides persistence for its objects (see “Databases and undoability” on page 64). Each database has an associated boss, called a command manager. When commands are used to change objects in a model, the command manager is responsible for executing the commands. Figure 11 shows that the application object model has several distinct databases that provide persistence for its objects. The diagram shows some of the objects in an InDesign session (with two open documents) and the databases with which these objects are associated. Each UIDbased object refers to its associated database through its IPMPersist interface. The defaults model, represented by an instance of kWorkspaceBoss, persists in the InDesign Defaults database file. Each document model, represented by an instance of kDocBoss, persists in an InDesign document database file. The session model, represented by the instance of kSessionBoss and the child objects that do not belong to any other model, persists in the InDesign SavedData database file. Each database has an associated command manager (see objects in Figure 11 that have an ICommandMgr interface). The command manager is responsible for managing database transactions and executing the commands that change the objects that persist in the database. If an object has an ICommandMgr interface, it is the root object of its associated database. This is shown in Figure 11. Key objects that are command managers are listed in Table 6; for the complete list, see ICommandMgr in the API Reference. NOTE: Commands The class that represents a database is IDataBase. This class is an abstract C++ class, but it is not an IPMUnknown interface. 73 Commands Command managers, databases, and undo support FIGURE 11 Models and databases in an indesign session (object diagram) UID 1 :kSessionBoss ICommandMgr ISession::QueryApplication UID 2 :kAppBoss ISession::QueryWorkspace IApplication::QueryDocumentList UID 3 :kDocumentListBoss UID 1 :kWorkspaceBoss ICommandMgr IDocumentList::GetNthDoc(0) IDocumentList::GetNthDoc(1) IPMPersist UID 1 :kDocBoss IPMPersist ICommandMgr IPMPersist InDesign SavedData : IDataBase 74 IPMPersist Untitled-1.indd : IDataBase UID 1 :kDocBoss ICommandMgr IPMPersist Untitled-2.indd : IDataBase IPMPersist InDesign Defaults : IDataBase Commands Command managers, databases, and undo support TABLE 6 Frequently Used Databases and their Support for Undoability Command manager / root boss class Database Undo support Example filename and use kSessionBoss Application SavedData None InDesign SavedData User interface objects like tools, menus, panels, dialogs, controls, and string translations. Objects that define the application object model, like plug-ins and boss classes. kWorkspaceBoss Application Defaults Full InDesign Defaults Default resources like swatches, fonts, and styles inherited by new documents. kDocBoss InDesign Document Full Your.indd Document content like spreads, pages, page items, and text. kBookBoss InDesign Book Partial Your.indb A collection of InDesign documents and associated resources. kCatalogBoss InDesign Asset Library Partial Your.indl A collection of page items. Clipboard/scrap Application ClipboardScrap Partial Each database has a level of support for undo which is fixed when the database is created and can be one of the following: z Full — The database fully supports undoable operations. The changes made by a transaction can be reversed automatically on undo and restored on redo. Undo and redo menu items are fully supported. z Partial — The database can undo only the most recent operation. If an error occurs, the database is rolled back to its state before the transaction began; however, once a transaction is committed, it is irreversible. There is no support for undo and redo menu items. z None — The database does not support undoable operations. There is no support for error handling, abortable command sequences, or undo and redo menu items. NOTE: Undo support varies by product. In InDesign and InCopy, full undo support is provided for documents and defaults. In InDesign Server, only partial undo support is provided for these databases; the server has no concept of user undo and redo. Objects that persist in a database with full or partial support for undo must be modified using commands. For example, a plug-in must process commands to change document content such as spreads, pages, or page items. Objects that persist in a database without support for undo can be modified by calling mutator methods on persistent interfaces directly. Commands are not required. For example, a plug-in can call interfaces on user interface objects, such as widgets, that set state directly. Commands 75 Commands The command processor The command processor This section describes how a command is passed through the application until it is processed. The session (see the ISession interface) has a singleton instance of the command processor (see kCommandProcessorBoss and the ICommandProcessor interface). The command processor is the core application component to which all commands are submitted via CmdUtils. The command processor’s structure is shown in Figure 12. A command targets one or more objects for change, and these objects persist in a particular database. Normally, client code creates a command instance and sets this target by passing parameters to the command (see “Command parameters” on page 69). The client code submits the command instance for processing using CmdUtils. Figure 13 shows the internal collaboration between the objects involved. FIGURE 12 Command processor (class diagram) «boss» kSessionBoss 1 ISession::QueryCommandProcessor 1 «boss» kCommandProcessorBoss ICommandProcessor 1 1..* «boss» kSomeCommandBoss ICommand «boss» kSomeModelRootBoss IDataBase::GetRootUID 1 IPMPersist::GetDataBase 1 ICommandMgr changes objects that persist in IDataBase The command processor examines the command and determines which database contains the objects the command changes. Each database has an associated command manager boss (see ICommandMgr interface), shown in Figure 12 as the boss class named kSomeModelRootBoss. For example, the root of the document model is kDocBoss, and kDocBoss is a command manager. The command processor calls the associated command manager to execute the command. 76 Commands The command processor Figure 13 shows the internal processing of a command. The call to process a command is passed to the session-wide command processor. This determines which database is targeted by the command, and the command is passed to the command manager for the specified database. The command manager processes the command, and the command updates an interface on a persistent (UID based) boss object. On completion, control returns to the client that initiated the process. FIGURE 13 CmdUtils Internals of command processing (sequence diagram) CommandProcessor A Command Manager A Command A Persistent Interface ProcessCommand ProcessCommand Do DoImmediate Set PreDirty The command is passed to the session wide command processor which determines the target database and calls ICmdManager::Do for that database. NOTE: Commands The command manager invokes the command. The command updates the persistent interface. Generally the command will derive from the Command class, providing an implementation of Do(). The persistent interface calls PreDirty before making any update to the data. Third party plug-ins should not interact directly with the command processor or command manager interfaces. CmdUtils provides all methods needed by third parties for processing commands. 77 Commands Scheduled commands Scheduled commands Commands can be scheduled for later processing, using CmdUtils::ScheduleCommand. The command is placed in a queue and processed when the application is idle as part of the main event loop, before idle tasks are processed. The sequence of calls involved in processing a scheduled command is shown in Figure 14. Compare this with the more normal case of immediately processing a command, shown in Figure 13. In Figure 14, the scheduled command is passed to the command processor (through the CmdUtils::ScheduleCommand call). At some later time, after all other processing is complete and control is returned to the main application event loop, all scheduled commands are processed. Guidance on using scheduled commands is in the “Commands” chapter of Adobe InDesign CS4 Solutions. FIGURE 14 CmdUtils Processing a scheduled command CommandProcessor A CmdManager A Command A Persistent Interface ScheduleCommand ProcessScheduledCmds ProcessCommand Do DoImmediate Set PreDirty Some client code schedules the command. The command is processed as part of the main event loop after all other processing has completed, and before idle tasks are processed. 78 Processing of a scheduled command is identical to that of a non-scheduled command. The only difference is with a non-scheduled command, client code is responsible for the initiation, upon completion, control returns to the client. With a scheduled command the event loop initiates processing, upon completion control returns to the main event loop. If a scheduled command returns an error, it is reported to the user, the error condition is cleared and processing resumes. Commands Snapshots and interface implementation types Snapshots and interface implementation types A snapshot is a copy of the state of an interface at a particular time. Undo and redo are achieved automatically by the application, which keeps snapshots of the interfaces changed within an undoable transaction. The snapshots are kept in the command history (see “Command history” on page 80) of the database with which the interface is associated. The way in which an IPMUnknown interface is implemented determines whether its data is persistent and/or needs a snapshot to support undo or redo: Commands z Regular interfaces store transient data that is not maintained on undo or redo. They are declared to the object model using CREATE_PMINTERFACE, and their state is lost if they are removed from memory. Data in a regular interface is not persistent, and no snapshot is taken. z Persistent interfaces are declared to the object model using the CREATE_PERSIST_PMINTERFACE macro. They serialize their state to their associated database via the ReadWrite method and can be removed from memory and returned again unchanged. Persistent interfaces that are part of a database that supports undo also are called to serialize their state (again via their ReadWrite method) to a snapshot. This mechanism is required to support undo and redo. See “Persistent interface” on page 89. z Snapshot interfaces store transient data that must be maintained on undo and redo. They are declared to the object model using the CREATE_SNAPSHOT_PMINTERFACE macro, and they serialize their state in a snapshot via the SnapshotReadWrite method. Snapshot interfaces are aggregated on a boss that persists in a database that supports undo; however, their data is not persistent. Data maintained by a snapshot interface is lost whenever the associated database is closed or when the command history for the database is cleared. See “Snapshot interface” on page 92. z Snapshot view interfaces are similar to snapshot interfaces, which also store transient data that must be maintained on undo and redo. The distinction is that a snapshot view interface depends on model objects that persist in another database. A snapshot view interface is part of a user interface object and must explicitly identify the database containing the model of interest. Also, the database on which a snapshot view interface depends can change. For example, a widget that tracks some state in the front document must change the database on which its snapshot view interface depends when the front document changes. Snapshot view interfaces are declared to the object model using the CREATE_VIEW_PMINTERFACE macro. See “Snapshot view interface” on page 99. z It also is possible to create a hybrid interface to allow the data that persists in the database to differ from the data of which a snapshot is taken for undo and redo. This can be used by complex data structures, like collections that need to optimize performance. Such an interface is declared to the object model using the CREATE_PERSIST_SNAPSHOT_PMINTERFACE macro. Data is serialized to the database via the ReadWrite method and to the snapshot via the SnapshotReadWrite method. For example, consider this approach if you have a collection of some sort and want to serialize only those objects that changed relative to the snapshot (rather than the entire collection). 79 Commands Command history Command history Consider a database to be the state of the persistent object model. For example, a document database is the state of the document object model (kDocBoss and all its dependents) at a particular time. Persistent interfaces (on dependent objects) are called to serialize their state to the database when necessary, via their ReadWrite method. The command history (ICmdHistory) provides a history of the undoable operations that were performed on each database. It records the state changes made by a particular command or command sequence, for the purposes of undo and redo. The name of the first command or command sequence processed to perform an operation on the model appears as a named step in the command history. These steps manifest as undo and redo menu items. The command history is used to automatically revert the state of affected objects on undo and to restore the changed state on redo. The database and its command history are related but distinct states. To maintain the command history, the database monitors which of its objects change when commands are processed. It tracks the UIDs that are deleted, created, or un-deleted. It tracks persistent interfaces, snapshot interfaces and snapshot view interfaces that are modified, and it takes snapshots of them. This information is kept in the command history as a set of CmdStackItem objects. (CmdStackItem is opaque on the SDK; third parties cannot access its data.) When undo is invoked, the application automatically reverts the database state to its previous revision, using this information. When redo is invoked, the application automatically restores the database state to its next revision. See Figure 15. The command processor (kCommandProcessorBoss) aggregates the command history (interface ICmdHistory), which is responsible for maintaining the state changes made by a particular command or command sequence (which manifests on the undo and redo menu). This state, represented as CmdStackItems, is used to move the model to previous and next states on undo and redo. The CmdStackItem encapsulates all data required for an undo and redo that occurred while processing a command or command sequence. 80 Commands Undo and redo FIGURE 15 Command history «boss» kCommandProcessorBoss The command processor aggregates a command history interface. 1 1 «interface» ICmdHistory 1 The command history maintains a set of CmdStackItems (opaque in the SDK). These items represent the set of UIDs added, deleted and modified. For the modified persistent interfaces, the changes are captured through a call to ReadWrite. Any UID based object that has an associated snapshot interface that has been modified, will have its state captured through a call to its SnapshotReadWrite. 0..* CmdStackItem On undo/redo, the state that is maintained in the CmdStackItem (opaque in the SDK), which is used to reset the UID based objects (through calls to ReadWrite and SnapshotReadWrite). Merging changes with an existing step in the command history Sometimes it is desirable to extend the scope of an existing step shown in the undo/redo menu to include functionality that occurs after the step finished. This can be done using either of the following: z A command with undoability of kAutoUndo. z A command sequence with undoability of kAutoUndo. Undo and redo To enable a user to undo or redo a change, the objects changed must: z Persist in a database that supports undo (see Table 6). z Be modified by processing commands. The application maintains the state required for undo/redo of changes made to persistent objects, as commands are processed. Each database that supports undo has a command history in which the necessary information is recorded, as described in “Command history” on page 80. Each persistent interface on a UID-based boss object has its ReadWrite method called to add the state to the command history (for undo and redo) and to the database (to persist its Commands 81 Commands Undo and redo state). On undo, the ReadWrite method is called to reset the state back to that from before the action, and on Redo, the ReadWrite method is called again to set the state back to that from the initial action. The sequence of calls to a persistent interface is shown in Figure 17. Snapshot interfaces are called on their SnapshotReadWrite method using a similar approach; see Figure 18. The command processor records in the command history the set of undoable operations it has performed (see the ICmdHistory interface on kCommandProcessorBoss). The steps in the command history appear in undo and redo menu items and are modelled internally using CmdStackItems. (These are internal only. Discussion is provided here to give some notion of how the command processor works.) This is shown in Figure 16. FIGURE 16 Command history internals (instance diagram) kCommandProcessorBoss CmdHistory Internals 1 1 «interface» ICmdHistory DB1: CmdStackItem1 DB2: CmdStackItem1 DBN: CmdStackItem1 DB1: CmdStackItem2 DB2: CmdStackItem2 DBN: CmdStackItem2 DB1: CmdStackItemN DB2: CmdStackItemN DBN: CmdStackItemN The command history maintains a stack of CmdStackItem objects for each database that supports undo; see Figure 16. A CmdStackItem (opaque in the SDK) represents the set of changes made by the sequence or command that manifests on the undo/redo menu. It contains data gathered during a database transaction for the purposes of undo and redo. On undo/redo, the “current” CmdStackItem is used to revert the state of the model. The CmdStackItem encapsulates all data required for an undo/redo that occurred while processing a command or command sequence. This includes all changes to persistent interface and snapshot interface data that were pre-dirtied. The CmdStackItem also maintains any inval handler cookies (see “Inval handler” on page 94) created as part of the sequence. 82 Commands Notification within commands Each step has a name of either a command or a command sequence that performed the operation. On undo, the application automatically reverts the database to its state before the operation was performed. On redo, the application automatically restores the database to its state after the operation was performed. Extension patterns involved in undo and redo The following extension patterns are called at undo or redo: z Persistent interfaces; see “Persistent interface” on page 89. z Snapshot interfaces; see “Snapshot interface” on page 92 (introduced in InDesign CS4). z Snapshot view interfaces; see “Snapshot view interface” on page 99 (introduced in InDesign CS4). z Inval cookies; see “Inval handler” on page 94 (introduced in InDesign CS4). z Observers, via their LazyUpdate method (introduced in InDesign CS4); see the “Notification” chapter. Notification within commands A command can initiate notification, so observers interested in changes to the objects it modifies are notified. See the “Notification” chapter. Commands also can be processed within observers and responders. Take care with commands that modify the model in this way. See the “Notification” chapter for further discussion of model changes within the context of notification. If you are implementing your own command, see “Command” on page 86 for additional information on notification in the command extension pattern. Error handling In response to a user gesture or another event, the application calls a plug-in to carry out an action. For example, the user creates a text frame. In this case, the plug-in creates and processes the commands that perform the action. On detecting an error, a plug-in normally sets the global error code (see ErrorUtils) to something other than kSuccess and returns. When control returns to the application, the global error code is checked. If it is set, the database is reverted to the state it had before the modifications began. Extension patterns that participated in the transaction being rolled back are called as follows: Commands 83 Commands Key client APIs 1. Persistent interfaces, snapshot interfaces, and snapshot view interfaces modified by the transaction are called to revert their state. See “Persistent interface” on page 89, “Snapshot interface” on page 92, and “Snapshot view interface” on page 99. 2. Inval cookies created during the transaction are called to undo. See “Inval handler” on page 94). When the application returns to its main event loop, it informs the user through an alert, using the string associated with the error code that is set (see “Error string service” on page 88). The global error code is then cleared, and the application continues. Plug-in code that processes commands or command sequences must check for errors. CmdUtils::ProcessCommand returns an error code that should be checked for kSuccess before continuing. Alternatively, you can check the global error code using ErrorUtils. Details are in the “Commands” chapter of Adobe InDesign CS4 Solutions. If a plug-in tries to process a command while the global error code is set, protective shutdown occurs to protect the integrity of the document or defaults databases (see “Protective shutdown” on page 84). Command implementation code also must check for errors. If a command encounters an error condition within the scope of its Command::Do method, it should set the global error code using ErrorUtils and return. Details on error handling is in the command extension pattern; see “Command” on page 86. Plug-in code that requires more sophisticated error handling, to allow for fail/retry semantics, must use an abortable command sequence. For information on using abortable command sequences, see the “Commands” chapter of Adobe InDesign CS4 Solutions. Protective shutdown Protective shutdown is a mechanism that helps prevent document corruption. Any attempt to process a command when the global error code is set (to something other than kSuccess) causes a protective shutdown. The application creates a log file describing the problem it encountered and then exits. Key client APIs This section summarizes the APIs a plug-in can use to interact with commands. Command facades and utilities There are many command-related boss classes named k<whatever>CmdBoss, but in many cases you do not need to instantiate these commands, as there are command facades and utilities in the API that encapsulate parameterizing and processing these commands. Interfaces like those in Table 7 are examples of command facades and utilities. These encapsulate processing of many commands required by plug-in code. These interfaces are aggregated 84 Commands Key client APIs on kUtilsBoss; the smart pointer class Utils makes it straightforward to acquire and call methods on these interfaces. You can call their methods by writing code that follows this pattern: Utils<IDocumentCommands>()->MethodName(...) TABLE 7 Useful command facades and utilities API Used for manipulating... IDocumentCommands Documents. IPathUtils Frames and splines. See the “Layout Fundamentals” chapter for other APIs that help with layout. IGraphicAttributeUtils Graphic attributes. See the “Graphics Fundamentals” chapter for other APIs that help with graphics. ITextModelCmds Text. See the “Text Fundamentals” chapter for other APIs that help with text. ITableCommands Tables. See the “Tables” chapter for other APIs that help with tables. IXMLUtils XML. See the “XML Fundamentals” chapter for other APIs that help with XML. kUtilsBoss See kUtilsBoss in the API Reference for a complete list of command facades and utilities. These utility classes abstract over low-level commands. Before using commands, always look for such a utility to see if there is a method that serves your purpose on one of these interfaces. By doing so, you avoid the increased chance of confusion and error that comes with processing commands. Your use case may require you to process some commands, if the utilities do not provide all of the functionality you require. As used in the application, command “facade” and “utility” are just different names for the same thing, a class that reduces and simplifies the amount of client code you need to write to change objects in the model. They decouple client code from command creation, initialization, and processing. When implementing custom commands, it is advisable to provide your own command facade or utility. If you want to share your class with other plug-ins, implement it as an add-in interface on kUtilsBoss; for example, see XDocBkFacade. If the class is used only by one plug-in, a C++ class is sufficient; for example, see BPIHelper. Commands 85 Commands Extension patterns Command-processing APIs The classes used when writing client code to process commands are listed in Table 8. TABLE 8 Useful classes for processing commands API Description CmdUtils Provides methods that create, process, or schedule commands and manage command sequences. PersistUtils Provides methods like GetDataBase, GetUID, and GetUIDRef, which are used to identify the objects to be operated on by a command. ErrorUtils Provides access to the global error code. NOTE: You must use CmdUtils to process commands. Do not use the ICommandProcessor or ICommandMgr interfaces for this. Misuse of these interfaces can easily cause document corruption. For information on finding and processing the commands provided by the API, see the “Commands” chapter of Adobe InDesign CS4 Solutions. Extension patterns This section summarizes the mechanisms a plug-in can use to extend the command subsystem. Command Description Suppose: z You added a new persistent boss to a document or a persistent interface to an object in a document, and you need to set custom data in these objects. z The API does not provide a command that sets the model data you need to change. z You want do some processing, and you concluded that a command provides the best pattern in which to encapsulate it. Architecture To implement a command, follow these steps: 86 z Define a new boss class in your plug-in that aggregates IID_ICOMMAND. If you require input parameters over and above the command’s item list, aggregate further data interfaces to the boss through which the parameters can be passed. z Provide an implementation of ICommand using Command as a base class. Commands Extension patterns z Add client code that processes your new command. See the “Commands” chapter of Adobe InDesign CS4 Solutions. z For more guidance, see the Command page in the API Reference and “Best Practice” below. Best practices Commands z The Do method contains the code that modifies the model. The model is changed by calling mutator methods on model interfaces, processing commands, processing commands in a command sequence, or calling utilities that process commands for you. z If you encounter an error condition within your Do method, set the global error code (ErrorUtils::PMSetGlobalErrorCode) and return. The application is responsible for reverting the model back to its state before the Do method was called and informing the user of the error. z If you need more sophisticated flow control that allows for fail/retry semantics, use an abortable command sequence (see IAbortableCmdSeq). z The Do method can change objects in only one database each time it is called. To change objects in more than one database in one undoable step, use a command sequence (ICommandSequence). z Normally, the database containing the objects to be changed is passed using the command’s item list. Alternatively, a command can target a predetermined database, by calling Command::SetTarget in its constructor. It also can override Command::SetUpTarget and determine the database containing the objects to be changed when the command is processed. z Normally, the DoNotify method contains the code that initiates notification, should you require it. Initiate notification by calling ISubject::ModelChange (not ISubject::Change). Calling ISubject::ModelChange when model objects are changed broadcasts regular and lazy notification (see the “Notification” chapter). The application calls DoNotify after the Do method of the command is called; however, notification need not be restricted to this method. z Notification can be performed for each object that was modified using the ISubject interface of affected objects. Notification also can be performed centrally. For example, many commands that modify the document model notify change using the ISubject interface of the document (kDocBoss). Sometimes commands use both these approaches. The benefit of using a centralized approach is that an observer needs to attach to only one subject to receive the notification. z If you need to pre-notify observers before the model is changed, call your DoNotify method from your Do method before making any changes to the model. z Notification can result in the processing of further commands, which can result in global error code being set. If further commands are processed, application shutdown occurs. If multiple subjects are notified by a command, the global error code should be tested between notifications. If the error code is set, the DoNotify method should return without calling further subjects, or it should consume the error and reset the global error code. z The undoability of a command should be fixed at command construction (see ICommand::GetUndoability). Its default value is kRegularUndo. If a different undoability is 87 Commands Extension patterns required, it should be set in the command’s constructor. See ICommand::Undoability in the API Reference. z A command must have a name (see Command::CreateName), if it has an undoability of kRegularUndo and it returns kTrue for IsNameRequired. Such commands can appear in undo and redo menu items. The name must have a translation, so it can be displayed in undo and redo menu items in a localized form. Commands with an undoability of kRegularUndo that override IsNameRequired to return kFalse must pick up their name from a subcommand. Some commands create and process other commands (subcommands) to make their changes and want to pick up the name of the first subcommand called within their scope instead of providing their own name. z Commands with undoability of kAutoUndo do not need a name, because their changes merge with an existing step in the undo and redo menu items. z The destructor of a command normally is empty. Do not change the model within the destructor. See also z For documentation on commands: Command and ICommand in the API Reference. z For documentation on notification: ISubject and IObserver in the API Reference. z If you need error codes set by your command to map onto strings that describe the error condition: “Error string service” on page 88. z For sample code: kBPISetDataCmdBoss, BPISetDataCmd, and BPIHelper from the BasicPersistInterface plug-in. Error string service Description Suppose error conditions can occur in your plug-in, and you need to inform the user of these errors. Architecture Sometimes, error conditions can occur in your plug-in, often within commands or command sequences. When control is returned to the application by your plug-in, and the global error code is set to something other than kSuccess, the user is informed and the model is reverted back to the last consistent state. An error string service provides the ability to map error codes onto error strings. To handle this, follow these steps: 88 z You Provide an error string service. This service allows ODFRez resources in your plug-in to map error codes onto strings that describe the error. Detailed documentation on how to define the error codes, resources, and implementations involved is the API Reference for IErrorStringService. z On detecting the error condition, call ErrorUtils::PMSetGlobalErrorCode to set your error and return control to the application. The application informs the user of the error. Commands Extension patterns See also For sample code: BPIErrorStringService from the BasicPersistInterface plug-in. Persistent interface Description Suppose you need to add custom data to an existing object in the model and have that persist. For example, you want frames in a document to have a set of custom properties that you control. Architecture The state of a persistent interface that is associated with a database that supports undo is captured by the application before it is changed; its state is reverted on undo and restored on redo. The state is saved in the command history (see “Command history” on page 80) for undo and redo, and in the database for persistence. Figure 17 shows the typical sequence of calls made to modify persistent interface, and when that modification subsequently is undone or redone. Commands 89 Commands Extension patterns FIGURE 17 Application core Sequence of calls to a persistent interface ICmdHistory CmdUtils A Command A Persistent Interface ProcessCommand DoImmediate Set PreDirty ReadWrite Push ReadWrite Undo ReadWrite Redo ReadWrite 90 Some entity processes a command which results in a PreDirty persistent interface being modified. The persistent interface calls PreDirty before mutating the data, which allows the application core to snapshot the state of the interface for the command history before it is changed (to allow the modification to be undone), and to require it to be Modify streamed to the database afterwards. The application calls on the persistent interface to stream its data to the database. On undo, the command history reverts the persistent interface to the state it had before the modification was made. On redo, the command history restores the persistent interface to the state it had after the modification was made. Commands Extension patterns To implement a persistent interface, follow these steps: 1. Aggregate your interface on the boss class in the model to which you want to add custom data that persists. Use an add-in interface (an ODFRez AddIn statement) if you are adding the interface to an existing boss class. To define a new type of persistent boss, see “Persistent boss” on page 91. 2. Provide an abstract interface that uses IPMUnknown as a base class. 3. Provide an implementation of this abstract interface. 4. Use CREATE_PERSIST_PMINTERFACE to make your implementation class available to the application (instead of CREATE_PMINTERFACE). 5. Define a ReadWrite method for your implementation class. It gets called to serialize your data when needed. 6. Call PreDirty within mutator methods before changing member variables that need to be serialized. This gives the application the ability to recognize that this interface is about to change. 7. Call mutator methods to update the state of your interface. The application calls your ReadWrite method to serialize your data when needed. NOTE: If your interface persists in a document, you must consider what should happen when users who do not have your plug-in open documents that contain your plug-in’s data. See the section on missing plug-ins in the “Persistent Data and Data Conversion” chapter. See also z “Command” on page 86. z For sample code: IBPIData, BPIDataPersist and BPISetDataCmd from the BasicPersistInterface plug-in. z For documentation on persistence: the “Persistent Data and Data Conversion” chapter. Persistent boss Description Suppose you need to add a new type of persistent object to the model. For example, you need to add a list of custom style objects to defaults. Architecture To implement a persistent boss that has a UID, follow these steps: 1. Define a new boss class. 2. Aggregate IID_IPMPERSIST, and use the kPMPersistImpl implementation provided by the API. Commands 91 Commands Extension patterns 3. Add persistent interfaces to the boss to store your custom data. See “Persistent interface” on page 89. 4. Choose a boss class to own the instances of your new persistent boss. Add a persistent interface into the boss class you have chosen that stores the UIDs of the new persistent boss. For example, to add custom styles to defaults, add this interface into kWorkspaceBoss. NOTE: If your boss persists within a database that supports undo, such as a document or defaults, you must create, modify, and delete the persistent boss using commands. Implement a create command to allocate a new UID for each new instance of the peristent boss, and store this UID in an interface on boss that owns it. The delete command deletes all child UIDs owned by the persistent boss, removes all references to the persistent boss from the model, then deletes the UID. See also z For sample code: kPstLstDataBoss and PstLstUIDList from the PersistentList plug-in. z For documentation on persistence: the “Persistent Data and Data Conversion” chapter. z “Command” on page 86. Snapshot interface Description Suppose you have an object containing transient data, which depends on model objects that persist in a database that supports undo, and: z Your object needs to be updated when the model objects are modified initially and on any subsequent undo or redo. z You cannot use lazy notification to update your object, because it must be kept up to date with changes to the model at all times. z Your object must be updated on undo or redo, before observers get called. For example, the text state (see the ITextState interface) caches the text attributes that are applied to the “text caret”; the next text insertion uses these attributes. This cache is implemented as a snapshot interface and maintained on undo and redo. Architecture The state of an snapshot interface is captured by the application before it is changed; its state is reverted on undo and restored on redo. The state is saved in the command history (see “Command history” on page 80) for undo and redo. Figure 18 shows a typical sequence of calls for a snapshot interface when it is modified, and when that modification is subsequently undone or redone. 92 Commands Extension patterns FIGURE 18 Application core Sequence of calls for a snapshot interface ICmdHistory An Observer A Snapshot Interface Update Set PreDirty PreDirty SnapshotReadWrite Push Some change causes an observer to be called which results in a snapshot interface being modified. The snapshot interface calls PreDirty before mutating the data, which allows the application core to capture the state of the interface for the command history before it is changed (to allow the modification to be undone). Modify Undo Undo SnapshotReadWrite On undo, the command history is invoked. This leads to a SnapshotReadWrite call on the snapshot interface, to revert the state of the interface back to the was it was before the modification. Redo Redo SnapshotReadWrite Similarly, on redo, the snapshot interface has the SnapshotReadWrite method called to restore the state to the way it was after the modification. Often, an observer or responder is used to modify a snapshot interface, as shown in Figure 18. Before changing any data, the snapshot interface implementation calls PreDirty, indicating to the application that the SnapshotReadWrite method should be called to capture the state of the interface (this state is associated with the CmdStackItem for the current sequence)). On undo Commands 93 Commands Extension patterns or redo, the SnapshotReadWrite method is invoked with the data associated with that particular sequence on the undo/redo menu. To implement a snapshot interface, follow these steps: 1. Add your interface to a persistent boss class that is part of the model on whose state your interface depends. Check that this class aggregates IPMPersist, since the boss must have a UID to support a snapshot interface. For example, if your object depends on objects in a document, you might choose kDocBoss. 2. Provide an abstract interface that uses IPMUnknown as a base class. 3. Provide an implementation of this abstract interface. 4. Use CREATE_SNAPSHOT_PMINTERFACE to make your implementation class available to the application (instead of CREATE_PMINTERFACE). 5. Define a SnapshotReadWrite method for your implementation class. It gets called to serialize snapshots of your data when needed. 6. Call PreDirty within mutator methods before changing member variables you serialize in SnapshotReadWrite. 7. When the model objects you depend on are changed, call mutator methods to modify the state of your interface. You might need to track the change to the object using regular notification. The application takes a snapshot of your interface, reverts the state on undo, and restores it on redo. NOTE: Even though this extension pattern is very similar in its implementation to a persistent interface, its effect is very different. The information in your snapshot interface is transient and not saved persistently with a document, defaults, or whatever other model it is associated. See also z For sample code: LnkWtchCache in the LinkWatcher plug-in and GTTxtEdtSnapshotInterface in the GoToLastTextEdit plug-in. z The “Notification” chapter. Inval handler Description Suppose you have an object that depends on model objects that persist in a database that supports undo, and: 94 z Your object must be updated at undo and at redo when the model objects it depends on change. z You cannot use lazy notification (see the “Notification” chapter) to update your object, because you need it to be kept up to date with changes to the model at all times. Commands Extension patterns z You cannot use a snapshot interface (see “Snapshot interface” on page 92) because you need to do more than restore the state of an object within the application. z You need to program behavior that runs at undo and redo. NOTE: This extension pattern is very rare. This is an advanced pattern and should be used only if absolutely necessary. For example, an observer might watch a subject that can be deleted from the model. Typically, such observers are attached to the subject when it is created and detached just before it gets deleted. If an object is created, the observer is attached. If there is an undo at this point, the observer should be detached; a subsequent redo should result in the observer being reattached. Similarly, if an object is deleted, the observer is detached. At this point, an undo should result in the observer being attached; a subsequent redo should result in the observer being detached. Consider an observer that attaches to a spread (see kSpreadBoss). When a spread is created, the observer gets attached to the new spread. If the creation of the spread is undone, this observer must be detached before the undo takes place. If the creation of the spread is redone, the observer must be re-attached after the redo takes place. The inval handler extension pattern allows for this. The GoToLastTextExit plug-in provides sample code that shows how to use an inval handler to manage the attachment and detachment of an observer that watches stories in a document. Architecture Inval handlers allow plug-in code to be called at undo and redo. There are two parts to the mechanism: z An inval handler (see IInvalHandler) that registers interest in a database that supports undo. z An inval cookie that gets called on undo and redo. The inval cookie is created by the inval handler at the end of a transaction that contained changes in which the plug-in was interested. Inval handlers are used in situations where a plug-in needs to achieve more than the restoration of the state (through persistent interfaces and snapshot interfaces), and the lazy notification broadcast occurs too late to meet this need. The plug-in has code that must be called immediately at undo or redo. To implement an inval handler, follow these steps: Commands z Provide an implementation of an inval handler (see the IInvalHandler class in the API Reference for details. See GTTxtEdtInvalHandler for sample code). z Provide an implementation of an inval cookie (see the IInvalCookie class in the API Reference for details. See GTTxtEdtInvalCookie for sample code). z Create an instance of the inval handler, and call DBUtils::AttachInvalHandler to associate this instance with the database that persists the objects in which you are interested. The scope of this association can be defined by the lifetime of the database or the enabling of particular functionality. For example, an inval handler might be attached to a database when a document is opened. 95 Commands Extension patterns z Once an inval handler is attached to a database, call DBUtils::StartCollectingInvals to indicate the inval handler is interested in participating in undo and redo. This usually occurs on some event (through an observer or some other means). The StartCollectingInvals call informs the database that the inval handler should be called at the end of the current transaction. If an undoable transaction is ongoing, the inval handler is said to be “collecting invals.” z The plug-in code records the semantics of the change. Where this is recorded is implementation-dependent: it could be in the state associated with the inval handler (recommended), an inval handler cookie, or elsewhere. z Further changes of interest can occur within the same transaction. The plug-in code should record the semantics of the changes; for example, by adding state to a list within the inval handler. z At the completion of the transaction, the IInvalHandler::EndCollectingInvals method is called. The inval handler can return an instance of an inval cookie representing the change(s) of interest that occurred. This inval cookie is kept in the command history for this database transaction. The inval handler is now said to be “not collecting invals.” z The inval cookie is called on undo and redo of the transaction. z When the lifetime of an inval handler is over, call DBUtils::DetachInvalHandler to detach the inval handler from the database. For example, an inval handler might be detached from a document database when a document is closed. Figure 19 shows the lifetime of a typical inval handler. Figure 20 shows the typical sequence of calls made to an inval cookie on undo. On undo, any inval cookies that were previously associated with the CmdStackItem are called. The inval cookie setting the error state aborts the undo (the model is reset to the state from before the undo). 96 Commands Extension patterns FIGURE 19 Typicalinval handler calls (sequence diagram) Application core ICmdHistory Observer (or other type of object) An Inval Handler An Inval Cookie Event that causes attach to the model new DBUtils::AttachInvalHandler An inval handler is created and associated with the database that persists the objects of interest. For example, an inval handler might be attached when a document is opened. Event in the model of interest for undo / redo AddInvalInfo(info) bool16= DBUtils::StartCollectingInvals StartCollectingInvals is called to indicate that the inval handler is interested in participating in undo and redo of a transaction. This usually occurs on some event (through an observer, or some other means). More events of interest for undo / redo can occur within the same transaction. The inval handler must be called to record each event. At the end of the transaction, EndCollectingInvals is called. The inval handler returns the cookie to be called on undo and redo of the transaction. See sequence diagram showing inval cookie calls. IInvalCookie*= EndCollectingInvals new AddInvalInfo(vector of info) Push New events in the model of interest for undo / redo cause the above sequence to be repeated and a new inval cookie to be associated with the transaction. Event that causes detach from the model DBUtils::DetachInvalHandler delete Commands When the lifetime of an inval handler is over, DetachInvalHandler is called to detach the inval handler from the database. For example, an inval handler might be detached when a document is closed. 97 Commands Extension patterns FIGURE 20 Application core Inval cookie calls on undo ICmdHistory Model An Inval Cookie Undo ErrorCode= InvalBeforeUndo Prior to the model state being reverted, all inval cookies are called. ReadWrite / SnapshotReadWrite After all inval cookies are called, the model is reverted (assuming no error). ErrorCode= InvalAfterUndo After the model has been reverted, all inval cookies are called. Setting error here will undo the "Undo". There are times where the lifetime of an inval handler does not match that of the command history. Inval handlers can be attached and detached at any time, asynchronously with anything else happening in the model. This means there are entries in the command history that do not have corresponding inval cookies for a particular inval handler. In this situation, the inval handler’s BeforeRevert_InvalAll and AfterRevert_InvalAll methods are used to provide the opportunity to rebuild the required state directly. There are times when an inval cookie instance can be asked to merge another instance. This causes the IInvalCookie::Merge method to be called, to merge cookies that were returned by each call to IInvalHander::EndCollectingInvals within one undoable transaction. For example, this can happen at the end of an abortable command sequence. See also 98 z IInvalHandler, IInvalCookie, DBUtils::AttachInvalHandler, DBUtils::StartCollectingInvals, and DBUtils::DetachInvalHandler in the API Reference. z For sample code: GTTxtEdtInvalHandler in the GoToLastTextEdit plug-in. z For documentation on how to detect change in other objects using observers and responders: the “Notification” chapter. Commands Extension patterns Snapshot view interface Description Suppose you have a user interface object like a widget, which has data that depends on model objects that persist in a database that supports undo, and: z Your data needs to be updated when the model objects it depends on are modified or when modifications are undone or redone. z You cannot use lazy notification to update your data, because it must be kept up to date with changes to the model at all times. NOTE: Use of this pattern is extremely rare in the application codebase. For example, it is used by interface ILayoutControlData on the layout widget. The data in this interface is depended on by many other objects and always must be kept in tight synchronzsation with the database. This is an advanced pattern and should be used only if absolutely necessary. Architecture A snapshot is taken of the state of a snapshot view interface, before it is changed, reverted on undo, and restored on redo. It is very similar to a snapshot interface (see “Snapshot interface” on page 92). The distinction is that the database with which a snapshot interface is associated is fixed and implicitly defined by the persistent boss on which it is aggregated. A snapshot view interface, on the other hand, is part of a user interface object and must explicitly identify the database containing the model objects on which it depends. Also, it is not one specific database. For example, a widget that tracks some state in the front document must change the database on which its snapshot view interface depends, when the front document changes. To implement a snapshot view interface, follow the steps described under CViewInterface in the API Reference. See also The CViewInterface template class in the API Reference. Commands 99 Commands Extension patterns 100 Notification Concepts Notification Notification patterns inform interested parties of certain changes. This chapter describes the prevalent notification patterns used by products in the InDesign family. Concepts Notification is a mechanism by which an interested object can be made aware of changes in other components or subsystems. This section focusses on two prevalent notification patterns, the observer and the responder. Observer pattern The observer pattern is described in [Design Patterns] by Gamma et al. The intent of the pattern is to “Define a one to many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.” Figure 21 shows the structure. FIGURE 21 Abstract representation of the observer pattern Subject Observer has observers Attach(Observer) : void Detach(Observer) : void 0..* Notify() : void Update() : void 0..* Notify() for all o in observers { o->Update() } The pattern consists of a subject and one or more observers. A subject is an object that needs to inform other objects that are interested in changes to the subject’s state. An observer is an object that needs to keep its state consistent with the state of a subject. A subject can have an association with multiple observers. An observer can observe multiple subjects. The association between observers and subjects is managed through Attach and Detach calls. Any change to the subject is declared through a call to the Notify method, which in turn calls Update on any associated observers. The subject supports three operations: Notification z Attach — Associates a specific observer with a subject. z Detach — Detaches a specific observer from a subject. z Notify — Notifies all associated observers of some change to the subject. 101 Notification Observers The observer supports one operation: z Update — Keeps the observer’s state consistent with the subject’s state. Typically, when a client wants to be notified of changes in a subject, it calls Attach, passing an observer that will be the recipient of update messages. Any update to the subject that could be of interest to observers results in a call to the subject’s Notify method. The subject, in turn, iterates through all attached observers, calling their Update operations. At any point, a client can remove the observer from the subject, using Detach. The observer no longer receives update events from that subject. For more information, see “Observers” on page 102. Responder pattern With the observer pattern, notification is provided when an object is modified. The responder pattern provides notification on an event. Notification consists of a signal sent from one party to a responder that can react to the event. The application predefines a set of events and corresponding signals in which responders can register interest. For example, signals are associated with document events like create, open, save, and close. A responder that registers interest in the document open event is called each time a document is opened. Figure 22 shows the structure. FIGURE 22 Responder pattern has responders SignalManager + SignalResponder() : void 1 0..* Responder + Respond() : void The pattern consists of a signal manager and responders. The signal manager is the object responsible for notifying responders of some event. A responder is an object that is called as a result of that event. A responder registers its interest in a particular event using the service provider extension pattern. A responder is a service provider, although this is not shown explicitly in Figure 22. For more information, see “Responders” on page 115. Observers This section describes the implementation of the observer pattern (see “Observer pattern” on page 101) within the application. The implementation consists of two interfaces, a subject (see the ISubject interface) and an observer (see the IObserver interface), as shown in Figure 23. 102 Notification Observers FIGURE 23 Subject and observer interfaces (class diagram) «interface» ISubject + + + + + + + + 0..* AttachObserver() : void Change() : void DetachObserver() : void ModelChange() : void «interface» IObserver 0..* + + + + AutoAttach() : void AutoDetach() : void LazyUpdate() : void Update() : void «realize» «realize» CSubject CObserver AttachObserver() : void Change() : void DetachObserver() : void ModelChange() : void A default implementation, kCSubjectImpl, is provided. It is unlikely that you would need to specialise it. + AutoAttach() : void + AutoDetach() : void + LazyUpdate() : void SomeObserver + Update() : void Subjects A subject is an object potentially of interest to other objects. Within the application, any object that maintains state of interest to other objects is a candidate for being a subject. An object with an ISubject interface is a subject. The interface supports the following key operations: z AttachObserver — Associates a particular observer with the subject. z DetachObserver — Detached a particular observer from the subject. z Change — Notifies observers of a change to the subject. Observers get called on their IObserver::Update method. See “Regular and lazy notification” on page 106. z ModelChange — Notifies observers of a change to a subject. Observers get called on their IObserver::Update method and/or their IObserver::LazyUpdate method. See “Regular and lazy notification” on page 106. Change manager Subjects within the application defer the functionality required to track the subject and observer dependencies to the change manager (the IChangeManager signature interface). The ISubject interface forms a facade over the change manager. It is unlikely third-party developers need to interact with the change manager directly. It is not considered further here. Notification 103 Notification Observers Observers An observer is an object interested in changes to a subject. Any object within the application object model can be an observer by aggregating the IObserver interface. The interface supports the following key operations: z AutoAttach and AutoDetach — Provided when the observer knows the subject with which it should be associated. A client would then delegate the association of subject and observer to the observer. See “Relating observers to subjects” on page 112 for a description of how to associate an observer with a subject. z Update and LazyUpdate — Receives notification when a subject changes. An observer can get called via its Update or LazyUpdate method, depending on how it chooses to receive notifications from the subject. See “Regular and lazy notification” on page 106. Message protocols Normally, an observer attaching to a subject indicates a protocol of interest. This protocol (identified by type PMIID) allows the observer to be called only for a subset of the total set of messages being broadcast by the subject. Generally, the protocol is synonymous with a data interface on the subject. Observers interested in changes to a specific data interface on the subject attach using the PMIID of the data interface. Figure 24 shows a subject, kSomeSubjectBoss, that aggregates a data interface, ISomeData. The observer, kSomeObserverBoss, is interested in changes to this data interface. The observer attaches to the subject, specifying IID_ISOMEDATA as the protocol of interest. This corresponds to the PMIID of the data interface. After the data interface is modified, the ISubject::ModelChange or ISubject::Change method is called to broadcast notification. Observers are called via their Update or LazyUpdate methods, with a message protocol of IID_ISOMEDATA. The object that actually modifies the data interface and calls the ISubject interface to broadcast notification is not shown in Figure 24. If the subject object is part of a document or defaults, the object that calls the mutator method on the data interface normally is a command (see the “Commands” chapter). The command calls ISubject::ModelChange if it performs notification. If the subject object is a user interface object, mutator methods on the data interface itself normally call ISubject::Change to broadcast notification. 104 Notification Observers FIGURE 24 A subject and an observer boss class (class diagram) «boss» kSomeBoss «boss» kSomeObserverBoss «interface» ISubject «interface» ISomeData + Get() : void + Set() : void + + + + AttachObserver() : void Change() : void DetachObserver() : void ModelChange() : void 0..* «interface» IObserver 0..* + + + + AutoAttach() : void AutoDetach() : void LazyUpdate() : void Update() : void «realize» «realize» «realize» SomeData CSubject CObserver + Get() : void + Set() : void + + + + AttachObserver() : void Change() : void DetachObserver() : void ModelChange() : void + AutoAttach() : void + AutoDetach() : void + LazyUpdate() : void SomeObserver + Update() : void Subject and observer types Within the application, subjects are split into distinct “types.” The type of object a subject is determines the method on ISubject that is called to perform notification. The types of subject are as follows: z Model — An object that is part of the document model (see kDocBoss), the defaults model (see kWorkspaceBoss), or another model that supports undo. The ISubject::ModelChange method is used to broadcast notification when model objects change. z User interface — An object that is part of the user interface; for example a checkbox or button This is distinct from an element in the user interface that is interested in model data. The ISubject::Change method is used to broadcast notification when user interface objects change. Within the application, observers are split into distinct “types.” The type of subject object an observer is watching determines the type of observer. The types of observers are as follows: Notification 105 Notification Observers z Model — An observer attached to objects that persist in a document (see kDocBoss), defaults (see kWorkspaceBoss), or another model that supports undo. Notification of model observers is done through a call to ISubject::ModelChange. z User interface — An observer attached to a user interface object; for example a checkbox or button. z Selection — An observer watching an artifact of the current application selection. z Context — An observer watching some context, such as the active document. z Hybrid — An observer watching multiple types of subjects. A particular observer may attach to any set of objects; however we do not consider what requirements observers that attach to multiple types of subjects might have. Regular and lazy notification The application supports two types of notification, regular and lazy. If an observer needs to be called as soon as a subject broadcasts the change message, it should request regular notification. If the observer can afford to wait until idle time before being notified that a change of interest occurred, it can register for lazy notification. When an observer attaches to a subject, it defines whether it wants to attach for regular notification, lazy notification, or both. Regular notification Regular notification is passed to an observer via the IObserver::Update method. With regular notification, an observer is called within the scope of the call to a subject’s ISubject::Change (or ISubject::ModelChange) method. Figure 25 shows the typical sequence of calls made when a subject notifies an observer using regular notification. 106 Notification Observers FIGURE 25 Regular notification A Client Object A Subject A Data Interface An Observer Set Change Update Get A client object is called and modifies some data interface, then broadcasts notification about the changes it makes. It mutates the state of a data interface and then calls ISubject::ModelChange. Observers get called via IObserver::Update and can retrieve the state of the data interface. The subject and the data interface are most often on the same boss object, but not always. If a change is undone or redone, the observer is not notified. That is, the Update message is not re-broadcast. See Figure 27 for the sequence of calls made on undo. Lazy notification Lazy notification is passed to observers via the IObserver::LazyUpdate method. Lazy notification is available only to observers of subject objects associated with persistent databases supporting undo. Lazy notification is used when observers do not need to be in tight synchronization with changes being made to the subject objects they observe. Rather than participating in each change that occurs on a subject object, observers using lazy notification are notified after all updates are made and the application is idle. When the state of an object in the model is changed (for instance, by a command), and notification is required, the notification always is broadcast by calling ISubject::ModelChange. The ISubject::ModelChange method queues a message to be broadcast later. Once the application is idle, observers get called with this message via the IObserver::LazyUpdate method, as shown in Figure 26. Notification 107 Notification Observers FIGURE 26 Application Idle Task Lazy notification A Command A Model Subject A Persistent Interface An Observer Do Set DoNotify ModelChange Observers using lazy notification are notified later on when the application is idle. LazyUpdate Get NOTE: The approach above holds for subject objects in the document model, the defaults model, or, in general, any subject object that persists in a database that supports undo. Only subject objects which persist in a database that supports undo can use lazy notification. Regardless of the number of changes made to the persistent interface, only one LazyUpdate call is made per sequence for a given message protocol. An implication of this is that ordering of lazy notification with respect to other lazy notification messages cannot be guaranteed. Lazy notification can be thought of as a message indicating a change was applied to an object some time in the past. The observer is responsible for determining the nature of the change. An observer that registers for lazy notification is not guaranteed to receive all messages. For example, suppose an observer is attached to a page item and is watching for the page item to move. If a sequence moves the page item and then deletes it, a lazy update message for the move is not sent to the observer. If a subject object is deleted, any lazy notification messages being queued for that object are purged. We recommend any model observer used to keep some user interface component synchronized with the model should use lazy notification. This eliminates any unnecessary refresh of 108 Notification Observers user interface data. An example use of lazy notification is a user interface panel that reports information about the set of text frames in a document. The user interface panel is associated with a model observer watching for textual changes or the addition or removal of text frames. These operations result in the panel being updated. There is no real requirement for the panel to be updated in real time as these changes are made; the panel should be updated when the text updates are complete (and the application is idle). Lazy notification enables this by sending a single IObserver::LazyUpdate message to the observer when the move is complete. If a change is undone or redone, the observer is notified; that is, the LazyUpdate message is rebroadcast. The sequence of calls made to an observer’s LazyUpdate method on undo is shown in Figure 27. FIGURE 27 Application Core Do DoNotify Sequence of calls made to an observer on undo ICmdHistory A Command A Model Subject A Persistent Interface An Observer Set ModelChange LazyUpdate Get The lazy update on do is discussed elsewhere Undo LazyUpdate Get On undo (and redo) the LazyUpdate method of the observer is invoked. Note, the command is no longer in existence when undo or redo is processed. Notification 109 Notification Observers Both notifications An observer can register for both regular and lazy notification. Figure 28 shows the sequence of calls this might involve. FIGURE 28 Application Idle Task Regular and lazy notification A Command A Model Subject A Persistent Interface An Observer Do Set DoNotify ModelChange Update Get Do Set DoNotify ModelChange Update Get LazyUpdate Get 110 Notification Observers While every ISubject::ModelChange message sent to the subject is propagated to the observer via IObserver::Update, only one IObserver::LazyUpdate call is made, regardless of the number of changes made in a single transaction. For example, if multiple updates are made on an object, the update messages being transmitted using a single protocol identifier, and the lazy update method is called only once. On undo or redo, only the LazyUpdate messages are re-broadcast. Registering for both notifications allows an observer to have the rich context of the Update message and have to re-build their view of the model only on rarer undo/redo events. Lazy notification data With regular notification, the observer (IObserver::Update) method is passed a context about what caused the change (usually, the command that initiated the notification). With lazy notification (IObserver::LazyUpdate), the observer gets notified only that something changed. The observer must be capable (for instance, by examining the model) of deducing or otherwise rebuilding the set of information it requires. In some cases, the time this takes causes performance issues; therefore, the API provides lazy notification data as an optimization. Lazy notification data objects are data-carrying (C++) objects created by the message originator. For example, a command that deletes a document page object (kPageBoss) might create a lazy notification data object and populate it with the UID of the deleted page. Generally, this lazy notification data object is passed to observers via IObserver::LazyUpdate. There are situations where the lazy notification data objects associated with a change are purged (for example, in low memory condition), and the observer is called with a nil-pointer; therefore it is important that observers be designed to deal with this. The lazy notification data objects used within the application are not documented in the public API. NOTE: Use of lazy notification data objects is not pervasive in the application. They exist only as an optimization, and the types of data they consist of varies. We recommend you avoid using them if possible and refresh the observer’s state entirely when IObserver::LazyUpdate is called. Observers and undo Only observers registered for lazy notification are signalled when an object they are associated with is modified through an undo or redo action. For each undo or redo, the observer receives one call (per message protocol), regardless of the number of changes made to the subject object. If the observer performs model modifications using commands (see “Model modifications” on page 114), on undo or redo these are automatically undone or re-done as required. For observers watching the model to update some aspect of the user interface, lazy notification should give the required update. If there are more exotic requirements for notification on undo and redo, two other patterns exist: see the Snapshot interface and Inval Handler extension patterns in the “Commands” chapter. Notification 111 Notification Observers Relating observers to subjects This section discusses how observers are attached to particular subjects. Determining the subject Before being able to attach and detach observers, an understanding of both the subject to attach to and the protocol to listen along is required. The sample code provided as part of the SDK has examples for many key events of interest. Similarly, Adobe InDesign CS4 Solutions has advice on detecting when events occur for domains like layout, text, XML, and so on. If neither of these resources provide the answer, the debug version of the application can be used. Under the test menu is an item called Test > Spy. It can be configured to log all executing commands, along with the subjects that are notified, the protocol used for notification, and the change that occurs. Perform the action of interest, and Spy provides the information required to observe the action. Attaching and detaching subjects In most situations, an observer understands the subjects in which it is interested and how to attach to them. Such an observer attaches to the subjects in the IObserver::AutoAttach call and detaches in IObserver::AutoDetach. For example, an observer on a panel can discover the widgets it contains (see the IPanelControlData interface) and attach to their subject interface. NOTE: The IObserver::AutoAttach and IObserver::AutoDetach methods still need to be called by another object. There are other situations where the observer does not know the subject(s) with which it should be associated. Given a subject and an observer, a client object can directly attach or detach the observer using ISubject::AttachObserver and ISubject::DetachObserver calls. Using a responder to attach and detach an observer Sometimes, an observer is required based on an action within the application. Responders (see “Responders” on page 115) are called on different application events and can be used to manage the association between an observer and a subject. For example, a responder can be called when documents are created, opened, or closed. On create or open, the responder can attach an observer to the document. On close, the responder can detach the observer. Using an observer to attach and detach another observer Sometimes, an observer attaches and detaches a second observer based on notification received by the first observer. This pattern commonly is seen in user interface objects that view objects in the front most document. The active context (see kActiveContextBoss, the IActiveContext interface, and the IID_IACTIVECONTEXT protocol) is the subject that is updated when the user chooses the document on which to work. The user interface object has a first observer that watches the active context. This observer attaches and detaches a second observer to the subjects of interest in the front-most document. 112 Notification Observers Observing a subject that can be deleted Sometimes, a client object needs to observe a subject created as part of an undoable action. To do this, a pattern involving two observers and an inval handler can be used (inval handlers are described in the “Commands” chapter). The first observer watches for create events for the subject and attaches the second observer to the newly created subject. To ensure this second observer gets detached if the create action is undone, the first observer also must set up an inval handler. The inval handler provides a mechanism to detach the observer on undo and reattach it on redo. Observing a subject that can be deleted as part of an undoable action is similar. On undo, the observer must be reattached; on redo, it must be detached. Again, this requires the use of an inval handler. Document notification The application supports a large object model. Any object is a candidate for becoming a subject (and thousands of subjects exist). Management of observers interested in the set of messages broadcast from a subject can be difficult, if many instances of a subject can exist. For example, consider objects in the page item hierarchy (which can be deleted and recreated, undone and redone, as a consequence of user actions). It is difficult and undesirable to maintain an observer on each page item. To solve this problem, as well as the actual subject object broadcasting the change message, the document’s subject also broadcasts the change. This means any observer associated with the ISubject interface on the document (kDocBoss) subject is notified, without the overhead of managing the association with finer-grained objects within the document. Notification of changes to page items are broadcast on the document subject using IPageItemUtils::NotifyDocumentObservers. Some other types of object use the ISubject interface of the document (see kDocBoss) directly to notify of a change. Observers and the model This section details some considerations around the use of model observers within the application. Observers “watch” model data for two primary reasons: 1. To update a user interface element to reflect the state of the model. (This type of observer is distinct from user interface observers, which watch for changes in user interface elements like checkboxes.) 2. To provide a point where existing functionality can be extended. For example, an observer can be used to set custom data in a story object (kTextStoryBoss), on story creation. There are side effects for both the error state and model modifications that should be considered when using observers to extend the model. Notification 113 Notification Observers Error state Model observers that extend functionality can set the global error state either directly (using ErrorUtils::PMSetGlobalErrorCode) or indirectly (through processing of commands). Generally, observers are notified during the processing of a command or sequence of commands. If the application tries to process a command when the global error state indicates anything but success (kSuccess), a protective shutdown is invoked to protect the integrity of open documents. An observer setting the global error state either aborts the current change (that is, the current change is undone) or causes the shutdown of the application. The behavior is determined on a per-use basis and can be complicated by the use of commands in different scenarios. For example, the creation of a text story object (kTextStoryBoss) can occur through the type text tool or from an import and place operation. The type text tool is straightforward, and an observer setting global error state causes the change to be undone. For import and place, however, the story creation occurs as part of a longer sequence of commands. A similar observer setting global error state causes an application shutdown as further commands are processed. Unless it is explicitly suggested that it is appropriate to set error state in an observer of a particular subject change, an observer should not set error state. Also, an observer that uses objects that potentially set error state (such as commands) should test for and consume any errors, taking appropriate remedial action. Model modifications A common pattern involves calling commands within an observer to make further modifications to the model. This can lead to problems. If the observer is notified as part of a sequence of commands, and the commands that are due to be processed after the current notification phase ends make any assumptions about the state of the model, instability and document corruption can result. For example, consider a sequence of two commands. The first inserts text into a text story object (kTextStoryBoss). The second changes the color of the newly inserted text to blue. Pseudo-code for this sequence is in Example 15 EXAMPLE 15 Pseudo-code showing dependencies between commands void MyTextUtils::AddNote(string str, ITextModel* story, TextIndex position) { int32 stringLen = str.Length(); BeginSequence("AddNote"); MyTextUtils::AddToStory(story,position,str,stringLen); MyTextUtils::SetTextColor(story,position,stringLen,BLUE); EndSequence("AddNote"); } At some point, a third party decides to extend the text functionality by writing a macro expander, the purpose of which is to expand known acronyms as text is entered into stories. The third party uses an observer that is notified when text is added to a story. If the observer modifies the model, specifically changing the number of characters entered into the story, it breaks the sequence in Example 15. The stringLen value is no longer valid. 114 Notification Responders If there is no risk of side effects from the model change within an observer (for example, the observer modifies custom data, not the core application data on the object), it is safe to proceed with the change. If there is a need to perform further modifications on the core application data, consider factoring the change to execute as a separate task (possibly on application idle). In Example 15, the observer might mark some custom, persistent data in the story, indicating it needs to be processed, and schedule a custom command. The custom command examines the story, determines whether the macro expansion operation is still valid, and updates the story if required. No assumptions can be made about what might occur between marking the story in the observer and the follow-on processing (for example, the document could close, further updates could occur, or the application could terminate). Commands that delete objects generally pre-notify, so subject observers get an opportunity to tidy up associated objects before the object is deleted. Observers called in this context should ensure the command state is CommandState::kNotDone. Responders This section describes the implementation of the responder pattern (see “Responder pattern” on page 102) within the application. The responder pattern provides notification that a specific event has occurred. For example, a responder can be called when a document is created, opened, or closed. Figure 29 shows the general structure. Notification 115 Notification Responders FIGURE 29 Pattern used for responders «boss» kASignalMgrBoss «interface» ISignalMgr CountResponders() : int32 Init(ServiceID) : void SignalNextResponder() : ErrorCode Terminate() : void «boss» kAResponderBoss 1 0..* «interface» IResponder Respond(ISignalMgr*) : void SignalFailed(ISignalMgr*) : void «realize» «interface» IK2ServiceProvider GetServiceID() : ServiceID «realize» «realize» SignalMgr CResponder AResponder CServiceProvider AResponderServiceProvider ServiceID: = kARespServiceID Respond(ISignalMgr*) : void ServiceID: = kARespServiceID The components to the responder pattern shown in Figure 29 are as follows: z Signal manager (signature interface ISignalMgr) — The entity responsible for notifying responders of an event. z Service provider (interface IK2ServiceProvider) — The entity that identifies the object as a responder and indicates the events of interest. z Responder (signature interface IResponder) — The entity invoked as a result of some event. Signal manager A signal manager is an object that controls the calling of responders. A boss class that has an ISignalMgr interface is a signal manager. A signal manager is called by some other object that wants responders to be notified when an event of interest has occurred. The object that calls a signal manager is often a command (see interface ICommand). For example, the command that opens a document calls the signal manager to notify responders which have registered an interest in this event. Responders are service providers. Each event for which a responder can be notified has a corresponding ServiceID. The application predefines a set of events and corresponding ServiceIDs in which responders can register interest. For example, the open document event has a ServiceID of kOpenDocSignalResponderService. See the “Notification” chapter of Adobe InDesign CS4 Solutions. 116 Notification Responders When a particular event occurs the signal manager is called to signal all responders that have registered interest. The signal manager uses the service registry (not shown in Figure 29) to find the responders that need to be called for the event. If a responder sets the global error state, the signal manager is responsible for calling previously signalled responders indicating there was an error condition (allowing the responder to take whatever action might be necessary) and the action is aborted. Responder A responder is a boss class that supports two specific interfaces, the service provider interface (IK2ServiceProvider) that identifies the events the responder is interested in, and the responder interface (signature interface IResponder) that is called for a particular event. Responder registration Each event for which a responder can be called has a corresponding ServiceID. A responder registers for one or more of these events by returning the ServiceIDs for the events of interest via its IK2ServiceProvider implementation. See the “Notification” chapter of Adobe InDesign CS4 Solutions for details on the predefined events the application makes available. For sample code, see the DocWchServiceProvider class in the DocWatch plug-in. Responder implementation The responder is called via IResponder::Respond on an event of interest. The Respond method performs whatever functionality is required and returns. If the global error state is set (ErrorUtils::PMSetGlobalErrorCode) by a responder, any previously signalled responders have their IRespond::SignalFailed method called to indicate failure. The SignalFailed method performs the function needed to recover. For example, if the Respond method attached an observer to an object, the SignalFailed method detaches that observer. Both methods receive a pointer to a signal manager interface, so they can find out information about the event. Typically, the Respond and SignalFailed methods query the signal manager interface for other contextual interfaces. For example, the document signal manager (see kDocumentSignalMgrBoss) provides context in the IDocumentSignalData data interface. Responders that register for document signals like kAfterOpenDocSignalResponderService use this data interface to access the document being opened. The Respond and SignalFailed methods often call the service manager using the ISignalMgr::GetServiceID method, to verify the ID of the service that occurred. This allows one responder implementation to be handle more than one type of event For sample code, see the DocWchResponder class in the DocWatch plug-in. Responders and the model Responder implementations can perform follow-on modifications to the model. For example, a responder called as the result of a command modifying the model can make further changes to the model by calling other commands. Notification 117 Notification Responders Take care that these modifications do not interfere with the model data on which the signal is based. For example, if a responder signalled on a create story signal (kNewStorySignalResponderService) deletes or otherwise modifies the created story, commands, observers, and responders that might follow the errant responder could make assumptions about the state of the story. Avoid direct modifications that interfere with the data on which a responder is based. If such a change is required, consider using the responder to set an associated, independent state that can be used by an idle task (or similar) to perform the actual modification on the model. This technique guarantees the model is in a consistent state before modifications are made. NOTE: A responder should check the global error state is kSuccess (ErrorUtils::PMGetGlobalErrorCode), before modifying the model. Responders and global error state Responders are designed to accommodate error; however, in practice, how a particular signal service deals with error state is implementation dependent. NOTE: If you set global error state in the IResponder::Respond method, thoroughly test all areas in the domain in which you are working. If a responder sets global error state, the signal manager calls all previously signalled responders via IResponder::SignalFailed and aborts the action. The ability to clean up a failed action is implementation and context dependent. For example, the creation of a text story object (kTextStoryBoss) can occur as a result of using the type text tool or importing a file. In the case of importing a file, the responder is called from a much deeper stack than in the case of using the type text tool. The implementation in the latter case does not handle aborting the import from a responder. Another implication of the IResponder::SignalFailed method being called on error is the method must be able to consume and take remedial action for any errors caused within the method. There is nothing the application core can do if an IResponder::SignalFailed method itself fails; the condition is indeterminate. Ordering of responders No guarantees can be made about the order in which responders are called to react to an event. If a client requires a particular responder to be called before another, the implementation of the second responder should call ISignalMgr::SignalResponder (identifying the first responder) at the start of its respond method. Even though the signal manager’s iteration of the responders has been short-circuited by calling one of the responders directly, no responder is called more than once. 118 Notification Key client APIs Responders and undo Responders for the predefined events made available by the application are not called at undo or redo of an operation. If a responder processes commands to make follow-on changes to the model, these changes are undone automatically as part of an undo operation; the client code need to manage this. The same is true for redo of an operation. If a responder is being used to attach an observer to a newly created model object, that observer must be detached on undo and reattached on redo. Similarly, if a responder is being used to detach an observer from a model object about to be deleted, that observer must be reattached on undo and detached on redo. To achieve this, the undo or redo actions need to be tracked using an inval handler. See the “Commands” chapter for a description of the inval handler extension pattern. If the responder is being used for a non-model based activity (for example, keeping a log of specific operations), and the undo or redo actions need to be tracked, an inval handler again is required. Key client APIs Table 9 shows key client APIs for observers and responders TABLE 9 Key client APIs for observers and responders API Observers Responders Notification Note IObserver Client code mainly calls AutoAttach and AutoDetach to have an observer attach or detach automatically to or from the subject(s) of interest. ISubject Client code mainly calls AttachObserver and DetachObserver methods to attach or detach an observer. ISignalManager If you are extending the application and need to signal new types of events to responders you will call the signal manager to perform the notification. Often this notification is performed by a custom command that you provide. Signal managers in the application use the default implementation, kSignalMgrImpl, provided by the API. This default implementation provides all functionality for the signal manager, it is unlikely that a third party developer would need to further specialize it. 119 Notification Extension patterns Extension patterns This section describes the mechanisms a plug-in can use to receive notification. User-interface widget observer Description This observer is attached to the subject object for a user interface artifact and called on a user interface event, such as selection of a checkbox or activation of a button. Architecture To implement a user interface observer, follow these steps: z Subclass the widget type you are creating (for example, kDialogBoss for dialogs), as described in the “User Interfaces” chapter of Adobe InDesign CS4 Solutions. z Provide an implementation for IObserver. The AutoAttach and AutoDetach methods should attach the observer to any sub-widgets (for example, all buttons on a dialog). Partial implementations exist; for example CDialogObserver for dialogs and CWidgetObserver for widgets. z User interface widget observers register for regular notification. Implement the IObserver::Update method to react to the user interface state change. See also z The “User-Interface Fundamentals” chapter. z The “User Interfaces” chapter of Adobe InDesign CS4 Solutions. z For sample code: PictureIcon/PicIcoRollOverButtonObserver and WListBoxComposite/WLBCmpListBoxObserver. Model observer Description A model observer provides an extension point for when a persistent object supported by an application database supporting undo is updated. Architecture To implement a model observer, follow these steps: 120 z Determine the subject that is to be observed, the protocol to listen on, and the change of interest. See the “Notification” chapter of Adobe InDesign CS4 Solutions. z Determine which boss class in the object model will aggregate the observer. Commonly, the boss class that represents the object being observed is a good candidate (for example, aggregating the observer on the document if you are interested in changes to the document). If Notification Extension patterns the observer relates to multiple subjects (for example, attaching to all open documents), place the observer somewhere accessible from client code. z Provide the implementation of IObserver, deriving from the CObserver partial implementation. z Determine whether it is appropriate to implement the AutoAttach and AutoDetach methods. Generally, these methods can be used if the subject object to be observed is known within the scope of the observer (for example, if the subject is on the same boss object as the observer). If the AutoAttach and AutoDetach methods are implemented, client code still needs to call them to create the dependency between subject and observer. If these methods are not provided, client code needs to manage the dependency between subject and observer directly (through the ISubject::AttachObserver and ISubject::DetachObserver calls). z Determine whether the subject object is maintained in a database that supports undo. If so, lazy notification is available. z If lazy notification is available, determine the type of notification required. If the subject object represents a UID-based object from a database that supports undo/redo, lazy notification is available. If the observer does not need to track every change to an object within a sequence of changes (for example, the observer is used to keep information in a user interface panel up to date, and the panel needs to be updated just once, after all changes are applied), lazy notification can be used. If the observer needs to be aware of all changes to the object as they occur, use regular notification. When attaching the observer to the subject (either in the AutoAttach/AutoDetach methods or through client code), specify the notification type. z If lazy notification is not available, register for regular notification. z Provide implementations of the IObserver::Update and/or IObserver::LazyUpdate methods, as required. See also Notification z “Relating observers to subjects” on page 112 z “Determining the subject” on page 112 z “Regular and lazy notification” on page 106 z For sample code showing a model observer using lazy notification: CustomDataLink / CusDtLnkUITreeObserver, LinkWatcher / LnkWtchActiveContextObserver, PanelTreeView / PnlTrvTreeObserver. z For sample code showing a model observer using regular notification: CustomDataLink/ CusDtLnkDocObserver, GoToLastTextEdit/GTTxtEdtNewDeleteStoryObserver, LinkWatcher/LnkWtchCacheManager, and PersistentList/PstLstDocObserver. 121 Notification Extension patterns Selection observer Description Selection observers provide an opportunity for client code to be called when there is a change in the active selection. For details, see the “Selection Observers” section in the “Selection” chapter. See also z “Selection Observers” section in the “Selection” chapter. z For sample code: TableAttributes/TblAttSelectionObserver, StrokeWeightMutator/StrMutSelectionObserver, BasicPersistInterface/BPISelectionObserver, and Persistent List/PstLstUISelectionObserver. Document observer Description As well as notifying a change on a subject, often the notification is repeated on the document for a subject. This allows observers to watch for a change of interest on a document (rather than attach/detach from every object within the document). For example, an observer interested in page items being moved around the layout does not need to attach to each page item (and detach if the page item is deleted, re-attaching if it is un-deleted, and so on), but attaches to the document instead. A document observer is a special example of a model observer, using the document object (kDocBoss) as the subject. See also z “Model observer” on page 120 z For sample code: CustomDataLink/CusDtLnkDocObserver, LinkWatcher LnkWtchCacheManager, and PersistentList/PstLstDocObserver. Active context observer Description A context observer is an observer that watches the active context. Architecture The active context object (kActiveContextBoss) is session wide and available from the session object (kSessionBoss) through the ISession::GetActiveContext call. An active context observer is an observer attached to the subject interface on the active context object. Active context notifications always are broadcast on the IID_IACTIVECONTEXT protocol. Only regular notification is available. The change context provided is another IID, indicating the type of 122 Notification Extension patterns contextual change that occurred. The common contextual changes of interest are shown in Table 10. TABLE 10 Types of context changes changedBy Note IID_IDOCUMENT The active document changed. IID_ICONTROLVIEW The active layout view changed (for example, when the document has multiple layout views open). IID_ISPREAD The current spread changed. IID_ISELECTIONMANAGER The type of selection changed. To implement a context observer, follow these steps: z Aggregate an observer on a boss class accessible from client code. z Provide implementations of IObserver::AutoAttach and IObserver::AutoDetach (attaching to the ISubject interface on the kActiveContextBoss accessible from the GetExecutionContextSession()->GetActiveContext() call). z Provide an implementation of the IObserver::Update method. The protocol ID is IID_IACTIVECONTEXT. Example 16 shows how to detect when the active document has changed. EXAMPLE 16 How to detect the active document has changed void MyObs::Update(const ClassID& theChange, ISubject* iSubj, const PMMID& protocol, void* changedBy) { if (protocol == IID_IACTIVECONTEXT){ InterfacePtr<IActiveContext> context(iSubj, UseDefaultIID()); IActiveContext::ContextInfo* info= (IActiveContext::ContextInfo*)changedBy; if(info->Key() == IID_IDOCUMENT){ HandleDocumentChange(context); } } } See also z Notification For sample code: LinkWatcher/LnkWtchActiveContextObserver. 123 Notification Extension patterns Subject Description If there is a need for a boss class to be observable, it needs to be a subject. Architecture To turn a boss class into a subject, follow these steps: z Aggregate the ISubject interface onto the boss class. z Provide the implementation for the interface. Generally, re-using the API-supplied implementation (kCSubjectImpl) is sufficient, and there should be no need for further specialization of this interface. See also z For sample code: PersistentList/kPstLstDataBoss. Responder Description A responder provides notification of an event, such as document open. Architecture To implement a responder, follow these steps: z Determine the event of interest (as described in the “Notification” chapter of Adobe InDesign CS4 Solutions). z Aggregate the service provider interface (IK2ServiceProvider) on a boss class. Either re-use an existing implementation (see the “Notification” chapter of Adobe InDesign CS4 Solutions), or provide an implementation that defines the set of ServiceIDs for the events of interest. z Aggregate the responder (IResponder) on the same boss class. z Provide an implementation for the responder, derived from the CResponder partial implementation. See also 124 z The “Notification” chapter of Adobe InDesign CS4 Solutions z For sample code: DocWatch/DocWchResponder, CustomDataLink/CusDtLnkDocResponder, and BasicPersistInterface/BPIDefaultResponder. Selection Concepts Selection This chapter describes the InDesign/InCopy selection architecture. The selection architecture is based on the concept of suites—abstract interfaces that allow client code to interact with an abstract selection. A suite remains neutral to the underlying format of the objects that are selected. Concepts Selection A selection is whatever is chosen or picked out. For instance, when a user selects a range of text with the Text tool, the user chooses a range of characters. In this case, the selection is a choice of characters from the text model. Highlighting in the user interface is incidental feedback that helps the user make the intended selection. Usually, making a choice using selection is a precursor to modifying the properties of the model underlying the selection. Selection primarily is about targeting objects on which to perform some action, and the selection subsystem exists to mediate changes to those objects. Selection format and target It is necessary to distinguish between the format of a selection and its content, the selection target. A selection format describes the model format of a selectable object, like the layout (frames), text, table cells, or XML structure. Each of these has a distinct arrangement of objects that represents its model. A selection target specifies a set of selected objects of a given selection format, like particular frames or a specific range of text. The principal goal of the selection subsystem is to hide all details about formats and targets from client code. Client code needs ask only, “Can this client code do this operation to the selection?” If yes, the client code can try to change the properties of the selection target. This encapsulation is achieved by means of the facade pattern discussed in “Design patterns” on page 126. InDesign 2.0 included support for a handful of selection formats, including layout objects (frames), text, table cells, and XML-structure items. InCopy CS added support for other selection formats, like notes. See Table 11. Selection 125 Selection Concepts TABLE 11 Selection formats and their targets Selection format When obtained Selection target Application defaults No documents are open. Global preferences Document defaults Document is open with nothing selected. Document preferences Galley text Insertion position is in text, or text range is chosen in Galley view. Range of characters in a text model (ITextTarget) Layout One or more page items are chosen in a layout view. Layout objects (see ILayoutTarget) Note Insertion position or text range is chosen in a note view. Range of characters in note text (ITextTarget) Story editor text Insertion position is in text, or text range is chosen in a story-editor view. Range of characters in a text model (ITextTarget) Table (table cells) One or more table cells are chosen in a layout view. Table cells in a table model (ITableTarget) Text Insertion position is in text, or text range is chosen in a layout view. Range of characters in a text model (ITextTarget) XML structure One or more nodes are chosen in an XML-structure view. Elements/attributes in the XML structure (IXMLNodeTarget) Design patterns A key task for a plug-in developer is writing model code that extends some aspect of the document model. For instance, if your principal requirement is adding private data to the layout model (see the BasicPersistInterface sample plug-in), the data added extends the layout model and persists with document contents. The command pattern, used in the application API to support undo and preserve document integrity, requires you to write further code to change your model. The API already uses the facade pattern, like ITableCommands and IXMLElementCommands, to hide the complexity of parameterizing and processing low-level commands. The selection architecture is an instance of the facade pattern, in that it makes client code easier to write by defining a high-level interface on top of the selection subsystem. The selection architecture shields client code from requiring detailed knowledge of what was selected in the selection subsystem. A facade also makes software maintenance easier, because a facade weakens the coupling between a subsystem and its clients. This weak coupling allows the subsystem components to be varied without necessarily affecting its clients. 126 Selection Selection architecture Selection architecture The most important objective of the selection architecture is to ensure that new selection formats can be added easily. To support new selection formats without rewriting large parts of the application, client code must be de-coupled from the selection format. Client code must not need to know the selection’s subject identifier, meaning client code must not need to know which objects are selected or any boss object associations in the underlying model (for example, the architecture of a text frame). Client code also must not need to know any commands that manipulate the objects. To achieve this goal, the selection architecture makes extensive use of suites that are neutral to selection format. A suite provides a high-level, model-independent API that encapsulates the details of the boss classes, interfaces, and commands in the underlying model. Clients interact with suites instead of directly with the selected objects. In programming terms, a suite is a layer of abstraction that sits on top of the selection and provides a narrow API through which client code communicates its intent with respect to the portion of the model selected. In design-pattern terms, a suite represents a facade that makes it easier to write client code. Writing code that sits on the model-manipulation side requires an understanding of the selection architecture and the model. Figure 30 shows the layers of encapsulation in the selection architecture. Client code communicates through suites on an abstract selection boss (ASB) class. In turn, these suites communicate with concrete selection boss (CSB) suites on one or more CSB classes. The CSB suites deal with the selection format of only their CSB, and they know how to access and change objects only in the part of the model the CSB manipulates. Selection 127 Selection Selection architecture FIGURE 30 Layers of encapsulation Client Client code uses the selection manager (ISelectionManager) to acquire a suite, and then calls one of its methods. Abstract selection: Client code is decoupled from the model by accessing attributes of the selection through an ASB. Selection subsystem::Abstract selection Concrete selection comprises one or more CSBs, each of which target the part of the model that underlies its selection format. Integrator suite forwards the method call to the corresponding CSB suite method on enabled CSBs. Selection subsystem::Concrete selection Model stores attributes in interfaces on boss objects. The attributes targeted by selection are selection attributes. CSB suite accesses interfaces on boss objects in the model or processes commands to change the model to do what this suite method does. Model A window can have one or more views that can support selection. Each view that uses selection instantiates a selection subsystem. In general, client code can remain unaware of what selection subsystem is in operation. While software developers need to be concerned about selection formats if they are writing code that manipulates the model, there is less need to be concerned about selection subsystems. For more information about selection subsystems, see “Selection architecture” on page 127. To write code that uses selection to choose attributes of the model to be displayed or changed, it is important to understand the structure that owns the selection format. To illustrate this, a schematic diagram of the selection subsystem used by the layout view (kLayoutWidgetBoss) to 128 Selection Selection architecture edit design documents is shown in Figure 31. It presents the static structure and highlights important boss classes and interfaces. FIGURE 31 ASB Selection subsystem used by layout view ASB: abstract selection IIntegratorTarget IXxxxSuite kIntegratorSuiteBoss Suite: interface that provides clients with a capability to access or change attributes of the selection. More generically, a suite acts on or reports information about the target. In the future, there may be subclasses of kIntegratorSuiteBoss that are not selection related. ISelectionManager kAbstractSelectionBoss kAbstractLayoutDocumentSelectionBoss Selection manager: Manages a selection subsystem. ITableSelectionSuite ITextSelectionSuite ILayoutSelectionSuite Layout CSB Text CSB ILayoutTarget IXxxxSuite kLayoutSuiteBoss IConcreteSelection kNewLayoutSelectionBoss Table CSB ITextTarget IXxxSuite kTextSuiteBoss kDocumentDefaultSuiteBoss kTableSuiteBoss IConcreteSelection kTextSelectionBoss Defaults ITableTarget IXxxxSuite IConcreteSelection kTableSelectionBoss CSBs: concrete selection boss classes that join this selection subsystem. Each CSB targets its selection format(layout, text, or tables). kDocWorkspaceBoss Defaults: Defaults are targeted when nothing is selected. The ASB provides the suites called by client code. In Figure 31, interface IXxxxSuite illustrates such a capability. The suite implementation on the ASB is an integrator suite; its responsibilities are described in detail in “Integrator suites” on page 142. For now, think of these suites as forwarding any calls they receive to corresponding suites on the CSBs. Further implementations of IXxxxSuite are provided on each CSB that supports the capability. These implementations are CSB suites; their role is discussed further in “CSB suites” on page 142 In Figure 31, you can see that IXxxxSuite is implemented on the layout CSB and the text CSB. This means layout and text selections have its capability. Also, when nothing is selected, client code still has the capability represented by IXxxxSuite, because the ASB then targets defaults and finds an implementation of the suite on kDocumentDefaultSuiteBoss. For more information on how to use suites to manage preferences, see “Selection architecture” on page 127. Table selections do not have the capability represented by IXxxxSuite, because there is no implementation of the suite on the table CSB. Selection 129 Selection Abstract selection bosses and suites ISelectionManager is the signature interface that identifies a boss class as an ASB. To obtain a suite, client code queries an ISelectionManager interface for the suite of interest. If the suite is available, its interface is returned; otherwise, nil is returned. The ASB is not a normal boss class; all suite interfaces are aggregated on the ASB, but an interface pointer is returned to client code only when an active CSB (or the default CSB) that supports the suite exists. The ASB uses a special implementation of IPMUnknown to control whether a query for an interface returns the interface or nil. Suite implementations get added to suite boss classes. The following suite boss classes are in Figure 31: z kDocumentDefaultSuiteBoss for defaults z kIntegratorSuiteBoss for the ASB z kLayoutSuiteBoss for the layout CSB z kTableSuiteBoss for the table CSB z kTextSuiteBoss for the text CSB A suite boss class has a target (like IIntegratorTarget or ILayoutTarget) and a collection of suite implementations. Figure 31 shows how the selection extends the suite boss classes. Other boss classes extend the suite boss classes in different ways. For example, scripting uses the suite boss kTextSuiteBoss to manipulate text content. Each box in Figure 31 is a self-contained, portable unit. This is one reason why the selection architecture is not coupled to a view, and CSBs do not have pointers to their ASB. This design allows re-use of suite boss classes by other features in the future. A catalogue of suite boss classes is provided in Table 22, in “Suite boss classes” on page 145. Each selection format has a CSB that extends its suite boss class. IConcreteSelection is the signature interface that identifies a boss class as a CSB. Only those CSBs that join the selection subsystem used by the layout view are shown in the Figure 31. Other CSBs exist and are used by other subsystems. For a complete list of all CSBs, see the API reference documentation for IConcreteSelection. To understand more about the responsibilities of a CSB, see “Concrete selection bosses” on page 131. Also, the ASB supports a set of interfaces that allows the selection content to be set programmatically. ISelectionManager provides the ability to select/deselect all objects. Each selection format provides an interface to allow the selection target to be varied. In Figure 31, for example, ILayoutSelectionSuite allows page items to be selected, and ITextSelectionSuite allows text to be selected. Abstract selection bosses and suites The selection architecture isolates client code from model code by means of an ASB. The ASB provides suite interfaces, which are collections of capabilities, as well as other interfaces needed for managing the selection. The main point to understand about the ASB is that it implements the facade for the selection subsystem. Client code interacts with the facade (a suite on the 130 Selection Concrete selection bosses ASB). Writing client code to take advantage of the selection architecture is straightforward; you need to understand only the facade. To write model code and code to change your model or the existing document model, however, it is important to understand how to interact fully within the selection subsystem, and this is less straightforward. The client code in Example 17 uses a parameter to determine the selection manager (ISelectionManager) to use by calling IActiveContext::GetContextSelection. The client code then queries for the suite of interest, IFooSuite. If the suite is available, the client checks to see if the capability it wants is enabled by calling IFooSuite::CanDoSomething. If so, the client uses the capability on the selection by calling IFooSuite::DoSomething. If someone were to create a new selection format and add support for IFooSuite, this client code would work. It does not need to know any details of how IFooSuite is implemented on any specific selection format. EXAMPLE 17 Client code using the selection architecture void FooActionComponent::DoAction(IActiveContext* ac, ActionID actionID...) { ... InterfacePtr<IFooSuite> iFooSuite(ac->GetContextSelection(), UseDefaultIID()); if (iFooSuite != nil && iFooSuite->CanDoSomething()) { iFooSuite->DoSomething(); } ... } In most cases, either client code is passed a parameter that identifies the selection manager to query for a suite, or the selection manager is implied by the kind of code being written. Concrete selection bosses A CDB is a boss class that encapsulates a selection format. It supports the manipulation and observation of the selected objects in the part of the model where the objects are located. This section describes the available selection formats and their associated CSB. The key properties of each CSB are tabulated. Table 12 describes the label for each field. TABLE 12 CSB description legend Selection Label Specifies CSB The boss class that represents this concrete selection. CSB name The name of the CSB that represents this concrete selection. Description A general description of this concrete selection. 131 Selection Concrete selection bosses Label Specifies Selection attribute extensibility Indicates whether this concrete selection can be extended to notify of changes to new selection attributes introduced by third-party software developers. Each CSB is responsible for defining the mechanism used to call selection extensions when selection attributes change. Some CSBs allow the mechanism to be extended. See “Selection extensions” on page 146 and “Selection observers” on page 147. Selection format The format of the objects this concrete selection makes selectable. Selection suite The interface that can specify the set of objects selected for this concrete selection. Suite boss class The boss class to which suites get added that extend the attributes that can be manipulated by this concrete selection. A list of all suites supported by the CSB is in the documentation for this boss class. Custom suites get added to the suite boss class. Target The interface that identifies the set of objects selected for this concrete selection. Layout selection Layout selections—made with the Selection tool or programmatically—are represented by the layout CSB. For examples of the suites available, see IGeometrySuite, ITransformSuite, and IGraphicAttributeSuite. For a complete list of available suites, see the API reference documentation for kLayoutSuiteBoss. Also see Figure 32 and Table 13. FIGURE 32 Layout selection containing a page item TABLE 13 Layout-selection CSB 132 CSB Name Layout CSB Selection format Layout objects like frames and other kinds of page items. CSB kNewLayoutSelectionBoss. Selection Concrete selection bosses Suite boss class kLayoutSuiteBoss. Target ILayoutTarget. Selection suite ILayoutSelectionSuite. Selection attribute extensibility Extensible. The CSB has a shared observer attached to the document’s subject (kDocBoss). Selection extensions define CreateObserverProtocolCollection to extend the protocols that are attached. Selection extensions define SelectionAttributeChanged to handle change broadcasts. Table selection Table selections—made with the Type tool or programmatically—are represented by the table CSB. For an example of a suite, see ITableSuite. For a complete list of available suites, see the API reference documentation for kTableSuiteBoss. Also see Figure 33 and Table 14. FIGURE 33 Table selection containing table cells TABLE 14 Table-selection CSB Selection CSB Name Table CSB Selection format Table cells. CSB kTableSelectionBoss. Suite boss class kTableSuiteBoss. Target ITableTarget. Selection suite ITableSelectionSuite. Selection attribute extensibility Extensible. The CSB has a cell focus (ICellFocus) that monitors table-attribute changes in the selection. Changes to custom table attributes also are detected by this CSB. Also, the CSB has a shared observer attached to the document’s subject (kDocBoss). Selection extensions define CreateObserverProtocolCollection to extend the protocols that are attached. Selection extensions define SelectionAttributeChanged to handle change broadcasts. 133 Selection Concrete selection bosses Text selection Text selections in the Layout view—made with the Type tool or programmatically—are represented by the text CSB. Text selection take one of two principal forms, a selected range of characters in a story (TextRange) or an insertion point within a story (represented by a TextRange with zero span). Although it may not seem intuitive that an insertion point is considered a text selection, it is considered a selection from the viewpoint of selection management. NOTE: Other views use other CSBs to represent text selection. For examples of the suites available, see ITextEditSuite and ITextAttributeSuite. For a complete list of available suites, see the API reference documentation for kTextSuiteBoss. Also see Figure 34, Figure 35, and Table 15. FIGURE 34 Text selection containing a tange of characters FIGURE 35 Text selection containing an insertion point TABLE 15 Text-selection CSB 134 CSB name Text CSB. Selection format Text. CSB kTextSelectionBoss. Suite boss class kTextSuiteBoss. Target ITextTarget. Selection suite ITextSelectionSuite. Selection Concrete selection bosses Selection attribute extensibility Extensible. The CSB has a text focus (ITextFocus) on kTextSelectionFocusBoss that monitors text-attribute changes; this picks up changes to custom text attributes. Also, the CSB has a shared observer attached to the document’s subject (kDocBoss). Selection extensions define CreateObserverProtocolCollection to extend the protocols that are attached. Selection extensions define SelectionAttributeChanged to handle change broadcasts. Figure 36 shows a text selection in a table cell. Although the selection is inside a table, this is a text selection and not a table selection. The selected text is indicated by the ITextTarget target interface. The table implied by this selection is indicated by ITableTarget, a secondary targeting interface provided by text selection. FIGURE 36 Text selection in a table cell Galley text selection Text selections in the galley view—made with the Type tool or programmatically—are represented by the galley-text CSB. The galley-text CSB represents text selection made in a galley view window. Text selection uses many subsystems. For the most part, client code can remain unaware of what subsystem is in operation, but suite developers need to know, because the CSB that supports text selection in the galley view is different than the one that supports it in the layout view. If you do not add your suite to the appropriate suite boss class, your suite might not be available when you want it. In most cases, the same suite implementation can be re-used. For an example of a suite that is available, see ITextEditSuite. For a complete list of available suites, see the API reference documentation for kGalleyTextSuiteBoss. Also see Figure 37 and Table 16. Selection 135 Selection Concrete selection bosses FIGURE 37 Galley text selection containing a range of characters TABLE 16 Galley text-selection CSB CSB name Galley text CSB. Selection format Galley text. CSB kGalleyTextSelectionBoss. Suite boss class kGalleyTextSuiteBoss. Target ITextTarget. Selection suite ITextSelectionSuite. Selection attribute extensibility Limited extensibility. The CSB has a text focus (ITextFocus) on kTextSelectionFocusBoss, which monitors text-attribute changes. Changes to custom text attributes are picked up by this. Story-editor text selection The story editor is available in InDesign and InCopy. Text selections by the story editor are similar to galley text selection. The story-editor CSB extends the galley-text CSB, and both share the same suite boss class, kGalleyTextSuiteBoss. For an example of a suite that is available, see ITextEditSuite. For a complete list of available suites, see the API reference documentation for kGalleyTextSuiteBoss. Also see Figure 38, Figure 39, and Table 17. FIGURE 38 136 Story-editor text selection in InCopy Selection Concrete selection bosses FIGURE 39 Story-editor text selection in InDesign TABLE 17 Story-editor text-selection CSB CSB name Story-editor text CSB. Selection format Story editor text. CSB kStoryEditorSelectionBoss. Suite boss class kGalleyTextSuiteBoss. Target ITextTarget. Selection suite ITextSelectionSuite. Selection attribute extensibility Limited extensibility. The CSB has a text focus (ITextFocus) on kTextSelectionFocusBoss, which monitors text attribute changes. Changes to custom text attributes are also picked up by this. Note text selection When text is selected in a note, the CSB involved is not the same as the one used for normal text selection. The note-text CSB represents text selection made in a note. For an example of a suite that is available, see INoteSuite. For the complete list of available suites, see the API reference documentation for kNoteTextSuiteBoss. Also see Figure 40 and Table 18. FIGURE 40 Note selection TABLE 18 Note text-selection CSB CSB name Selection Note text CSB. 137 Selection Concrete selection bosses Selection format Note text. CSB kNoteTextSelectionBoss. Suite boss class kNoteTextSuiteBoss. Target ITextTarget. Selection suite ITextSelectionSuite. Selection attribute extensibility Limited extensibility. The CSB has a text focus (ITextFocus) on kTextSelectionFocusBoss, which monitors text attribute changes. Changes to custom text attributes are also picked up by this. XML selection XML selections in the structure view (the left panel of Figure 41)—made with the Selection tool or programmatically—are represented by the XML CSB. There is a selection subsystem associated with the XML structure view that is distinct from the selection subsystem associated with the layout view, even though both views are displayed in the same window. Do not confuse XML selection with the XML tags shown in the layout view (the right panel of Figure 41). For examples of suites that are available, see IXMLStructureSuite and IXMLTagSuite. For a complete list of available suites, see the documentation for kXMLStructureSuiteBoss. Also see Figure 41 and Table 19. FIGURE 41 XML node selections in XML-structure view TABLE 19 XML-selection CSB 138 CSB name XML CSB Selection format XML node (element, attribute, or both) CSB kXMLStructureSelectionBoss Selection Concrete selection bosses Selection Suite boss class kXMLStructureSuiteBoss Target IXMLNodeTarget Selection suite IXMLNodeSelectionSuite Selection attribute extensibility Not extensible. 139 Selection Concrete selection bosses Document defaults When a document is open but nothing is selected, the document workspace (kDocWorkspaceBoss) becomes the selection subsystem’s target. For more information, see “Selection architecture” on page 127. Also see Figure 42 and Table 20. FIGURE 42 Document defaults: open document with no selection TABLE 20 Document-defaults CSB 140 CSB name Defaults. Selection format Preferences maintained as data interfaces on kDocWorkspaceBoss. CSB kDocWorkspaceBoss. (Strictly speaking, this is not a CSB, because it does not aggregate IConcreteSelection; however, kDocWorkspaceBoss often is referred to as the defaults CSB.) Suite boss class kDocumentDefaultSuiteBoss. Target NA Selection suite NA Selection attribute extensibility Extensible. The CSB has a shared observer attached to the document workspace’s subject (kDocWorkspaceBoss). Selection extensions define CreateObserverProtocolCollection to extend the protocols that are attached. Selection extensions define SelectionAttributeChanged to handle change broadcasts. Selection Concrete selection bosses Application defaults When no document is open, a special selection subsystem (the workspace selection, kAbstractWorkspaceSelectionBoss) is activated. It targets application-wide defaults on kWorkspaceBoss. For more information, see “Selection architecture” on page 127. Also see Figure 43 and Table 21. FIGURE 43 Application defaults: no document open TABLE 21 Application-defaults CSB Selection CSB name Defaults. Selection format Preferences maintained as data interfaces on kWorkspaceBoss. CSB kWorkspaceBoss. (Strictly speaking, kWorkspaceBoss is not a CSB, because it does not aggregate IConcreteSelection; however, kWorkspaceBoss often is referred to as the defaults CSB.) Suite boss class kApplicationDefaultSuiteBoss. Target NA Selection suite NA Selection attribute extensibility Extensible. The CSB has a shared observer attached to the session workspace’s subject (kWorkspaceBoss). Selection extensions define CreateObserverProtocolCollection to extend the protocols that are attached. Selection extensions define SelectionAttributeChanged to handle change broadcasts. 141 Selection Integrator suites Integrator suites An integrator suite is an implementation of a suite that was added to kIntegratorSuiteBoss, which is part of an ASB. Consequently, an integrator suite sometimes is known as an ASB suite. All communication between client code and the selection is performed using the integrator suite. A properly designed suite API is neutral to selection format, meaning there are no references to a specific selection format. This is essential to avoid tight coupling between the client code and the model. The purpose of an integrator suite is to iterate over the concrete-selection formats supported by the suite or, more formally, to integrate over the integrator target (represented by IIntegratorTarget). Although it may seem that “iterator” may be a more appropriate name, “integrator” is correct in this context, because it means “to join together.” In the mathematical sense, “integrate” also can refer to summation, and the integrator suite performs a summation over the capabilities of individual selection-format-specific suites. The implementation of an integrator suite is very stereotypical; it delegates any call to CSB suites on CSBs that are active (i.e., on CSBs that have a selection). Integrator-suite implementations should be based on templates provided by the SDK. The templates reduce the amount of code you need to write. An example of an integrator suite is the kTableSuiteIntegratorImpl implementation of ITableSuite on kIntegratorSuiteBoss. Both text (kTextSuiteBoss) and table selections (kTableSuiteBoss) provide support for ITableSuite. The client code is shielded from the selection format that is providing the implementation. Integrator suite calls are forwarded to the selection-format–specific implementations on the CSB suites. CSB suites A CSB suite is a suite implementation on a CSB. CSB suites receive calls forwarded from integrator suites when they are called by client code. CSB suites exist to do model-specific work, like navigating relationships between objects in the model and processing of commands. When you manipulate the model from within a CSB suite, you interact with objects in a specific selection format (e.g., by means of target interfaces like ITextTarget or ILayoutTarget). There are several CSBs that extend suite-boss classes; for example, kTextSelectionBoss subclasses kTextSuiteBoss. For a complete list of CSBs, see the API reference documentation for the IConcreteSelection interface, from which you can examine the documentation page for each CSB to see which suite boss it extends. 142 Selection Encapsulation Encapsulation A key concept in the selection architecture is that client code should be insulated from code that accesses and modifies the model (both the document and associated data). Code that works in terms of UID, UIDRef, or UIDList values that relate to stories (kTextStoryBoss objects) or layout objects (for example, something that exposes an IGraphicFrameData interface) interacts with a portion of the document model. A selection of objects that is represented, for example, as a UIDList (as would have been the case in the old selection architecture) is tightly coupled to the model. Such tight coupling makes it very difficult to add new selection formats, because client code already has detailed knowledge about what is in a selection. Also, with such tight coupling, you cannot change the way in which the model is represented without breaking client code, because the client code has detailed model knowledge. To add new selection formats, the client code needs to be de-coupled from the selection formats. This means client code should be neutral with respect to selection format when dealing with the selection. The client code communicates by means of ASB suites. These suites, in turn, communicate with CSB suites. The CSB suites deal only with the model format of their CSB; they do not even know about the ASB. This is necessary because an alternative use for suites is scripting, which most likely does not have an analog to the ASB. Suites and the user interface: an example In the StrokeWeightMutator sample plug-in, the stroke-weight drop-down widget is enabled when the stroke weight of whatever is selected can be changed. These steps are followed: 1. The widget looks for the API’s stroke attribute suite (IStrokeAttributeSuite). 2. If the suite is available, a CSB (the one with something selected or the defaults, if nothing is selected) has an implementation of the suite. 3. The widget asks the integrator suite on the ASB whether the stroke-weight attribute is available, by calling IStrokeAttributeSuite::GetStrokeWeightCount. 4. The integrator-suite implementation on the ASB forwards the call to the CSB-suite implementations. 5. The CSB implementation accesses the model for the selection format it supports and returns the answer. 6. The widget then calls IStrokeAttributeSuite::GetStrokeWeight to retrieve the value if applicable. When the widget handles a user click to change the stroke weight, the widget calls IStrokeAttributeSuite::ApplyStrokeWeight on the integrator suite to dispatch to the CSB suites, which change the value stored in the model. The widget synchronizes what it displays with any Selection 143 Selection Responsibilities changes to the selection using a selection observer. It is sent a message when the stroke weights displayed in the widget need to be refreshed. (See “Selection observers” on page 147.) Responsibilities Basic client-code responsibilities If you are writing client code that modifies the properties of an abstract selection and can use a pre-existing suite, your responsibilities are minor. Query the selection manager (ISelectionManager) that represents the abstract selection for the suite you want (like ITextAttributeSuite to change properties of text in a selection) and, if you get the suite, use it. Look for a code fragment showing these responsibilities for the ITextMiscellanySuite suite. You must understand how to query the abstract selection for a particular capability. To understand what suites are provided by the API, see the API reference documentation and examine the boss classes that aggregate ITextMiscellanySuite, to see the selection formats that support this particular capability. Selection-observer responsibilities If you are writing code that needs to update when the selection changes, implement a selection observer (see “Selection observers” on page 147). If there is a pre-existing suite that informs your client code of the changes you are interested in, your selection observer looks for messages from this suite. For example, ITextAttributeSuite notifies clients when a text-attribute change happens to the selection. Otherwise, implement a custom suite to inform client code about the changes of interest (see “Custom suites” on page 145). Custom-suite responsibilities If you have any client code that depends on the state of the selection, write a custom suite to access that state. For example, the BasicMenu sample implements a custom suite because it has menu items that need to know whether a page item is selected. A suite is required because the client code needs to access a selection target interface to determine whether a page item is selected. If you are writing code that changes the existing document model (for example, you are implementing or processing commands that change this model), and you want to use selection to target the objects, you must create a suite. If you are writing code that extends the document model (for example, you are adding a custom data interface to the layout model, like BasicPersistInterface), and you want to use selection to target the manipulation of this data, you must create a suite. The model also extends to default preferences; changes to the application’s default preferences and the document default preferences can be mediated by the selection subsystem. 144 Selection Custom suites Custom suites When writing a custom suite that you want to make available to client code in one or more selection formats, provide two implementations, one relating to abstract selections and another to concrete selections. The former (see “Integrator suites” on page 142) is added to the kIntegratorSuiteBoss suite boss class, and the latter (see “CSB suites” on page 142) is added to the selection-format-specific suite boss classes. For details about the selection formats that can be of interest to client code, see “Concrete selection bosses” on page 131. Table 22 lists suite boss classes. TABLE 22 Suite boss classes Suite boss class Selection format Rationale kApplicationDefaultSuiteBoss Application defaults If you want your suite to be available to client code when no documents are open, add the suite to this boss class. kDocumentDefaultSuiteBoss Document defaults If you want your suite to be available to client code when a document is open but nothing is selected, add the suite to this boss class. kGalleyTextSuiteBoss Text in InCopy Galley or Story Editor views (ITextTarget) If you want your suite to be available to client code during galley- or story-editor-view text selections, add the suite to this boss class. kIntegratorSuiteBoss Abstract (IIntegratorTarget) Required for any custom suite. kLayoutSuiteBoss Layout (ILayoutTarget) If you want your suite to be available to client code during layout selections, add the suite to this boss class. kNoteTextSuiteBoss Text in InCopy Note (ITextTarget) If you want your suite to be available to client code during note selections, add the suite to this boss class. kSelectionInterfaceAlwaysActiveBoss If you want your suite to be available to client code regardless of the kind of concrete selection that exists, add the suite to this boss class. kStoryEditorSuiteBoss Text in Story Editor view (ITextTarget) (Not supported.) If you want the story editor suite to be different from that for InCopy Galley view, add the suite to this boss class. kTableSuiteBoss Tables (ITableTarget) If you want your suite to be available to client code during table selections, add the suite to this boss class. Selection 145 Selection Selection extensions Suite boss class Selection format Rationale kTextSuiteBoss Text (ITextTarget) If you want your suite to be available to client code during text selections, add the suite to this boss class. kXMLStructureSuiteBoss XML structure, (IXMLNodeTarget) If you want your suite to be available to client code during XML selections, add the suite to this boss class. Selection extensions A selection extension (ISelectionExtension) is a bridge between a suite implementation with an unknown interface and the selection architecture. A suite that requires advanced function registers a selection extension with the selection subsystem. The selection subsystem then communicates with the extension, which in turn forwards a message to the suite implementation. If your suite requires one or more of the services described in this section, you must implement a selection extension. Caches A suite may need to cache data to improve performance. You can add caches to suite implementations. In general, caches are added to CSB suite implementations. Cache validation should be delayed as long as possible. Rather than updating the cache every time a model change occurs, declare a Boolean cacheValid flag. When the model changes, set the flag to kFalse. Before accessing the cache, rebuild it if it is invalid. Thus, if your suite provides data to a user-interface panel and that panel is not visible, your suite does not needlessly consume CPU cycles recalculating cache values the user does not need. Furthermore, caches should be enabled only on CSB boss classes, not suite boss classes. Because the scripting architecture extends suite boss classes, no caching should be done on them. If you are implementing a custom suite that needs a cache, add your cache interface only to the CSB. IConcreteSelection is the signature interface that identifies a boss class as a CSB. Your custom suite implementation can then perform a run-time check to see if your cache interface is available. If not, it can handle this situation gracefully and carry on without using the cache. Selection change notification The design of some suites requires notification of selection changes. A selection extension allows your suite to be called by a CSB whenever the selection changes. A selection extension allows you to control whether clients of your suite—in the form of selection observers—get notified. (See section “Selection observers” on page 147.) 146 Selection Selection observers There are two kinds of selection change events: z An object is added to or removed from the selection (that is, the selection changes); for example, a user Shift-clicks to add a frame to the selection. z An attribute of an object in the selection changes (that is, a selection attribute changes); for example, the stroke color of selected frames changes. A suite that has a cache must mark its cache as invalid when notified the selection has changed. A suite needs to invalidate its cache when notified that a selection attribute changed only if the specific selection-attribute change affects this suite's cache. Many selection-attribute changes may not affect a particular cache. NOTE: Selection-attribute change notification is not supported on all CSBs. For information on each CSB, see “Concrete selection bosses” on page 131. Initialization Some suites need to perform an action on start-up or shut-down of a selection subsystem. Any such initialization is done by implementing a selection extension. Do not confuse this kind of start-up and shut-down with application services, like IStartupShutdownService, which are called for the application session. Selection subsystems get created and destroyed as the views that own them open and close. Communication with Integrator suite Rarely, a CSB implementation needs to communicate with its integrator. Because there is no pointer on the CSB back to the integrator, a messaging system was created: IConcreteSelection::BroadcastToIntegratorSuite. Selection observers As described in “Selection change notification” on page 146, there are two kinds of selection change event: selection-changed event and selection-attribute-changed event. A selection observer (ActiveSelectionObserver) is the abstraction that allows client code to be called when a selection-changed event occurs. For more information, see the SelectionObserver.h header file. Suites that need to communicate extra data to selection observers during the selection-changed event implement a selection extension. Suites that need to include information about a selection-attribute–changed event also implement a selection extension. (See “Selection extensions” on page 146.) When a selection-changed event occurs, a selection observer’s ActiveSelectionObserver::HandleSelectionChanged member method is called. On receiving this call, an observer can take action. For example, the observer can update some data displayed in a user-interface widget. Selection 147 Selection Selection-utility interface (ISelectionUtils) Optionally, before taking action, the observer can examine the message parameter (ISelectionMessage) and look for extra data placed there by a suite. When a selection-attribute–changed event occurs, a selection observer’s ActiveSelectionObserver::HandleSelectionAttributeChanged member method is called. On receiving this call, an observer must call ISelectionMessage::WasSuiteAffected before taking action. There are many kinds of selection attributes, and they can be given meaning only by the CSB suite. It examines the broadcast from the selection format that changed (originating from a command notification that the model was updated), then passes a model-independent message about the change to selection observers. A selection observer may be called when any attribute of the selected objects changes, so a selection observer can receive messages that do not affect it. The selection observer must filter these calls, so it does not needlessly take action and waste CPU cycles. For sample code, see BasicPersistInterface. Selection-utility interface (ISelectionUtils) A utility interface for selection (ISelectionUtils) is provided on kUtilsBoss. For detailed information on the member methods, see the API reference documentation for ISelectionUtils. Some member methods provided by ISelectionUtils allow you to access the active selection. Most client code does not need to depend on the active selection, because client code normally is given access to the selection manager to use. If you want the active selection, ISelectionUtils::GetActiveSelection returns the selection manager from the active context. There also are other member methods, like QueryActiveLayoutSelectionSuite and QueryActiveTextSelectionSuite, that depend on the active selection manager; these should be used only by client code that needs to work with the active selection. 148 Layout Fundamentals Terminology Layout Fundamentals This chapter describes the features and supporting architecture of the layout subsystem, as well as how a client can use these features and the layout-related extension patterns in the InDesign API. For use cases related to layout, see the “Layout” chapter of Adobe InDesign CS4 Solutions. Terminology See the “Glossary” for definitions of terms. Table 23 lists terms used in this chapter and sections that relate to them. TABLE 23 Terminology Term See ... Bounding box “Bounding box and IGeometry” on page 190 Child “Parent and child objects and IHierarchy” on page 155 Content page item “Page items” on page 173 Current spread “Current spread and active layer” on page 197 Document “Documents and the layout hierarchy” on page 152 and “Spreads and pages” on page 157 Document layer “Layers” on page 161 Frame “Frames and paths” on page 173 Front document “The layout presentation and view” on page 194 Front view “The layout presentation and view” on page 194 Geometric page item “Coordinate systems” on page 183 Graphic frame “Frames and paths” on page 173 Graphic page item “Graphic page items” on page 177 Group “Groups” on page 178 Guide “Guides and grids” on page 180 Layer “Documents and the layout hierarchy” on page 152 and “Layers” on page 161 Layout hierarchy “Spreads and pages” on page 157 Layout view “Layout view” on page 196 Layout Fundamentals 149 Layout Fundamentals Concepts Term See ... Layout presentation “The layout presentation and view” on page 194 Master page, Master spread “Documents and the layout hierarchy” on page 152 and “Master spreads and master pages” on page 168 Page “Documents and the layout hierarchy” on page 152 and “Master spreads and master pages” on page 168 Page item “Documents and the layout hierarchy” on page 152 and “Page items” on page 173 Pages layer “Spreads and pages” on page 157 Parent “Parent and child objects and IHierarchy” on page 155 Path “Frames and paths” on page 173 Publication “Spreads and pages” on page 157 Spread “Documents and the layout hierarchy” on page 152 and “Spreads and pages” on page 157 Spread layer “Layers” on page 161 Text frame “Frames and paths” on page 173 Text page item “Text page items” on page 177 Transformation matrix “Transformation matrices” on page 183 Concepts Figure 44 shows a facing-pages publication with three pages arranged over two spreads. The document is presented for edit in the layout presentation. The Pages panel is used to edit the spreads and pages, including the master spreads and master pages. The Layers panel is used to edit the layers. 150 Layout Fundamentals Concepts FIGURE 44 Layout presentation Layout concepts Document Page item (empty graphic frame) Spread Page item (text frame) Page Pasteboard Pages palette Layers palette Master spread and master pages Layer Some basic terms are given below. A full layout-related glossary is in “Terminology” on page 149. z Document — An InDesign document, unless otherwise stated. z Layer — The abstraction that controls whether objects in a document are displayed and printed and whether they can be edited. A layer can be shown or hidden, locked or unlocked, arranged in front-to-back drawing order, etc. A page item is assigned to a layer. If a layer is shown, its associated page items are drawn; if a layer is hidden, its associated page items are not drawn. Layers affect an entire document: if you alter a layer, the change applies across all spreads. z Layers panel —The user interface for creating, deleting, and arranging layers. z Layout presentation — The user-interface window in which the layout of a document is presented for viewing and editing. The layout presentation contains the layout view and other widgets that control the presentation of the document within the view. z Master page — A page that provides background content for another page. When a page is based on a master page, the page items that lie on the master page also appear on the page. A master page eliminates the need for repetitive page formatting and typically contains page numbers, headers and footers, and background pictures. Layout Fundamentals 151 Layout Fundamentals Documents and the layout hierarchy z Master spread — A special kind of spread that contains a set of master pages. z Page — The object in a spread on which page items are arranged. z Page item — Represents content the user creates and edits on a spread, like a path, a group, or a frame and its content. z Pages panel — The user interface for creating, deleting, and arranging pages and masters. z Spread — The primary container for layout data. A spread contains a set of pages on which page items that represent pictures, text, and other content are arranged. The pages can be kept together to form an island spread, a layout that spans more than one page. Documents and the layout hierarchy This section introduces the data model on which the layout subsystem is based. The boss classes and interfaces that represent spreads, pages, and page items in a document are described in general. Architecture This section shows how the items introduced in “Concepts” on page 150 are represented by boss classes and interfaces in a document. Figure 45 shows the overall arrangement. 152 Layout Fundamentals Documents and the layout hierarchy FIGURE 45 Layout-hierarchy class diagram 1 IMasterSpreadList «boss» kDocBoss ILayerList 1 1 ISpreadList Represents a master spread. Represents a document. Represents a spread. 1..* «boss» kMasterPagesBoss 0..1 2..* 1..* <<extends>> «boss» kSpreadBoss «boss» kDocumentLayerBoss 1 1 Represents a layer. 4..* IHierarchy ISpreadLayer «boss» kSpreadLayerBoss IMasterPage IHierarchy 1..10 1 «boss» kPageBoss Represents a page or master page. Note: A page doesn't own the content that lies upon it; the spread owns the content. 0..* «boss» kGuideItemBoss Represents a ruler guide. 2 IHierarchy 0..* «boss» kGroupItemBoss Represents a group. 0..* «boss» kSplineItemBoss Represents a frame or path. Graphics or text page items can be nested inside a frame. A document (kDocBoss) comprises one or more spreads (kSpreadBoss) and master spreads (kMasterPagesBoss). The ISpreadList interface lists the spreads. The IMasterSpreadList interface lists the master spreads. Each spread contains one or more pages (kPageBoss), ruler guides (kGuideItemBoss), frames (kSplineItemBoss), paths (kSplineItemBoss), or groups (kGroupItemBoss). These objects are arranged in a spread in a tree represented by the interface IHierarchy. Frames and groups have additional page items nested within them. The objects in a layout are layered, and this layering is reflected within each spread. A layer is represented by a document layer (kDocumentLayerBoss) that has two corresponding spread layers (kSpreadLayerBoss) in each spread. The document layers are listed by the ILayerList interface; the spread layers are the immediate children of a spread on the IHierarchy interface. A spread (kSpreadBoss) contains 2n spread layers as children, where n is the number of document layers. All the immediate children of a spread must be spread layers (kSpreadLayerBoss). Figure 45 showed a document has at least two layers: z The pages layer — Pages (kPageBoss) always are associated with the pages layer. The pages layer is represented by the document layer (kDocumentLayerBoss) found at index 0 in the ILayerList interface. It has two corresponding spread layers (kSpreadLayerBoss) in each Layout Fundamentals 153 Layout Fundamentals Documents and the layout hierarchy spread. The spread layer that owns the spread’s pages (kPageBoss) is found at child index 0 in the spread’s hierarchy (IHierarchy); the other spread layer, which is always empty, is found at child index 1. z A layer for content. The remaining layers—and there always is at least one other layer in the ILayerList interface— are the layers to which guides (kGuideItemBoss), frames (kSplineItemBoss), paths (kSplineItemBoss), and groups (kGroupItemBoss) can be assigned. Each of theses layers is represented by a document layer that has two corresponding spread layers. When a page item is assigned to belong to a particular layer, the object becomes owned by the corresponding spread layer through IHierarchy. Changes to document layers are document-wide, meaning changes to document layers affect all spreads, including master spreads in the document. For more information about layers, see “Spreads and pages” on page 157 and “Layers” on page 161. Figure 45 also shows that master spreads (kMasterPagesBoss) have the same organization as spreads. A master spread (kMasterPagesBoss) contains master pages (kPageBoss), which provide background content for other pages. Master spreads form their own hierarchy, and each page connects to its master by the interface IMasterPage. For more information, see “Master spreads and master pages” on page 168. The key interfaces involved in the layout data model are summarized in Table 24. For more information, see the API reference documentation for these interfaces. TABLE 24 Key interfaces in the layout data model 154 Interface Note IDocumentLayer Signature interface for a document layer (kDocumentLayerBoss). Stores a document layer’s properties. Has an associated content-spread layer and guide-spread layer. IHierarchy Connects boss objects in a tree that represents a layout hierarchy. Provides a mechanism to find parent and child objects and interfaces. See “Parent and child objects and IHierarchy” on page 155. ILayerList List of document layers (kDocumentLayerBoss) in a document. A layer is represented by a kDocumentLayerBoss object that has two associated kSpreadLayerBoss objects in each spread. IMasterPage Stores the master spread (kMasterPagesBoss) associated with a page (kPageBoss) and the index of the master page within the master spread on which this page is based. IMasterSpread Signature interface for a master spread (kMasterPagesBoss). Stores the name of a master spread and contains the incremental information that defines a master spread. This information is beyond what is contained in a spread. IMasterSpreadList List of the master spreads (kMasterPagesBoss) in a document. Layout Fundamentals Documents and the layout hierarchy Interface Note ISpread Signature interface for a spread (kSpreadBoss). Contains useful methods for discovering the page items that lie on a page or spread and for navigating between document layers (kDocumentLayerBoss) and spread layers (kSpreadLayerBoss). A document is laid out as a set of spreads in which each spread contains one or more pages and other page items. ISpreadLayer Signature interface for a spread layer (kSpreadLayerBoss). A spread layer is the container for the page items in a layer through the IHierarchy interface on the kSpreadLayerBoss. The ISpreadLayer interface maintains a relationship back to the corresponding document layer boss (kDocumentLayerBoss). ISpreadList List of the spreads (kSpreadBoss) in a document. The SnpInspectLayoutModel code snippet can inspect the layout hierarchy. Run the snippet in SnippetRunner to create a textual report for a document. See SnpInspectLayoutModel for sample code that examines the layout hierarchy in various ways. Parent and child objects and IHierarchy A page item can contain other page items. The containing object is the parent; the contained objects are the children. Child index order defines z-order, the order in which objects draw; the child with index 0 draws first (behind), and the child with index n-1 draws last (in front). This association between page items is implemented by the IHierarchy interface, as shown in Figure 46. FIGURE 46 Page Item parent-child composition (class diagram) 0..* «boss» kPageItemBoss children 1 parent IHierarchy kPageItemBoss is the abstract base class for objects that participate in the layout hierarchy. IHierarchy is a required interface. Subclasses of kPageItemBoss include spreads (kSpreadBoss), spread layers (kSpreadLayerBoss), and frames (kSplineItemBoss). To see all subclasses, see the API reference documentation for kPageItemBoss. Each subclass of kPageItemBoss may have different constraints on the number and type (boss class) of children it can contain. The child objects contained within the parent are said to be nested. Figure 47 shows an example. The object diagram is an example of how the internal representation changes when a circle is nested inside a square using cut and paste. The parent-child association between boss objects in a layout is realized by the IHierarchy interface. When the circle is cut, the association with its Layout Fundamentals 155 Layout Fundamentals Documents and the layout hierarchy initial parent, the spread layer, is broken. When the circle is pasted, it is associated with its new parent, the square. The square becomes a frame, because it now contains the circle. The drawing of the circle is then clipped to its frame. FIGURE 47 Change in parent-child relationships when a circle is nested in a square g Above: The original circle and square paths. Below: The parent-child relationships between the boss objects that represent these paths on a spread. g Above: The circle cut and pasted into the square. «boss» spread1 : kSpreadBoss Below: The changed parent-child relationships. The square is the parent of the circle. parent child «boss» layer1-content : kSpreadLayerBoss «boss» circle : kSplineItemBoss parent child «boss» layer1-content : kSpreadLayerBoss parent child «boss» spread1 : kSpreadBoss child «boss» square : kSplineItemBoss parent child «boss» square : kSplineItemBoss parent child The parent-child associations are represented by the IHierarchy interface. «boss» circle : kSplineItemBoss The low-level commands used to edit the hierarchy programmatically are kAddToHierarchyCmdBoss and kRemoveFromHierarchyCmdBoss. A utility interface, IHierarchyUtils, provides a facade that processes these commands. For more information, see the API reference documentation. The boss objects in the hierarchy illustrated above can be visited using a recursive function, as shown in Example 18: 156 Layout Fundamentals Spreads and pages EXAMPLE 18 Recursive function that visits each child boss object in a hierarchy void VisitChildren(IHierarchy* parent) { int32 childCount = parent->GetChildCount(); for (int32 childIndex = 0; childIndex < childCount; childIndex++) { InterfacePtr<IHierarchy> child(parent->QueryChild(childIndex)); #ifdef DEBUG // Trace the boss class name of the child. DebugClassUtilsBuffer className; DebugClassUtils::GetIDName(&className, ::GetClass(child)); TRACEFLOW("LayoutFundamentals", "%s\n", className); #endif // Add code to examine other interfaces on the boss object. VisitChildren(child); } } Spreads and pages A spread is the primary container for layout data. A spread contains a set of pages on which the page items that represent pictures, text, or content of another format are arranged. A spread owns all the objects it contains, including its pages, ruler guides, frames, paths, groups, and any nested content. The objects in a spread are organized into layers, so the user can control whether the objects assigned to a layer should be displayed or editable. See Figure 48 for the user’s perspective. The publication shown is a facing-pages document with one spread, one page, and one layer. Layout Fundamentals 157 Layout Fundamentals Spreads and pages FIGURE 48 Spread User’s perspective of a sample spread and page Page Layer Figure 49 is an object diagram showing the layout-related boss objects that exist in a publication containing a ruler guide and graphic frame on a page. The sample document (kDocBoss) contains a spread (kSpreadBoss), page (kPageBoss), graphic frame (kSplineItemBoss), and ruler guide (kGuideItemBoss). The content of the spread is layered on spread layers (kSpreadLayerBoss) that map onto corresponding document layers (kDocumentLayerBoss). There are two document layers (kDocumentLayerBoss), the pages layer and layer 1. The page, graphic frame, and ruler guide are arranged on spread layers (kSpreadLayerBoss) under the spread’s IHierarchy interface. 158 Layout Fundamentals Spreads and pages FIGURE 49 Document containing a frame and ruler guide on a page «boss» layout-d : kDocBoss ISpreadList::GetNthSpreadUID(0) ILayerList::QueryLayer(0) «boss» spread1 : kSpreadBoss ILayerList::QueryLayer(1) «boss» pages : kDocumentLayerBoss «boss» layer1 : kDocumentLayerBoss IHierarchy::QueryChild(3) IHierarchy::QueryChild(0)IHierarchy::QueryChild(1)IHierarchy::QueryChild(2) «boss» pages : kSpreadLayerBoss IHierarchy::QueryChild(0) «boss» page1 : kPageBoss «boss» private : kSpreadLayerBoss «boss» layer1-content : kSpreadLayerBoss «boss» layer1-guides : kSpreadLayerBoss IHierarchy::QueryChild(0)IHierarchy::QueryChild(0) «boss» graphic-frame : kSplineItemBoss «boss» ruler-guide : kGuideItemBoss A layer is represented by a kDocumentLayerBoss object with two corresponding kSpreadLayerBoss objects in each spread. The pages layer is the layer to which pages (kPageBoss) are assigned. In Figure 49, the pages layer is represented by the kDocumentLayerBoss object named “pages” and the kSpreadLayerBoss objects named “pages” and “private.” The pages document layer (kDocumentLayerBoss) always is at index 0 in the layer list (ILayerList). The first child on the spread’s hierarchy always is the associated page’s spread layer and contains the spread’s pages (kPageBoss). The second child of the spread is a private spread layer that always is empty. Pages are drawn behind all other objects, because they always are stored on the spread’s hierarchy at child index 0. Note the pages layer is not shown in the Layers panel. Layout Fundamentals 159 Layout Fundamentals Spreads and pages In Figure 49, Layer 1 is represented by the kDocumentLayerBoss object layer1. It has two corresponding spread layers (kSpreadLayerBoss) on the spread’s hierarchy, one for content (layer1-content, which stores the graphic frame (kSplineItemBoss)) and one for ruler guides (layer1-guides, which stores the ruler guide). The order of these spread layers can vary, depending on whether guides are being drawn behind or in front of content. Figure 49 illustrates the order when guides are drawn in front of content. NOTE: Child index order in IHierarchy defines z-order, the order in which objects on those spread layers (kSpreadLayerBoss) draw. The child with index 0 draws first (behind); the child with index n-1, last (in front). The code shown in Example 19 visits each child boss object of the spread shown in Figure 49. (For the implementation of VisitChildren, see Example 18.) All boss objects on the spread’s hierarchy are visited by the code in Example 19, including spread layer and page boss objects. EXAMPLE 19 Code that iterates spreads and visits their children using IHierarchy void VisitSpreadChildren(UIDRef& documentUIDRef) { InterfacePtr<IDocument> document(documentUIDRef, UseDefaultIID()); InterfacePtr<ISpreadList> spreadList(document, UseDefaultIID()); IDataBase* database = documentUIDRef.GetDataBase(); int32 spreadCount = spreadList->GetSpreadCount(); for ( int32 spreadIndex = 0; spreadIndex < spreadCount; spreadIndex++ ) { UIDRef spreadUIDRef(database, spreadList->GetNthSpreadUID(spreadIndex)); InterfacePtr<IHierarchy> spreadHierarchy(spreadUIDRef, UseDefaultIID()); VisitChildren(spreadHierarchy); } } In contrast, the code shown in Example 20 filters the objects by the pages on which they lie. The method ISpread::GetItemsOnPage calculates which items lie on a page. Since pages do not own the items that lie on them (spreads own the items), the calculation of which items lie on a page is geometrical, comparing the intersection of the bounding box of each item with the bounding box of the page. (For details, see ISpread::GetItemsOnPage.) If this code is run on the spread shown in Figure 49, the only object that appears in the list itemsOnPage is the graphic frame. The ruler guide is not returned as an item, because it is a pasteboard-ruler guide; if the ruler guide were a page-ruler guide, the code in Example 20 would list it. 160 Layout Fundamentals Layers EXAMPLE 20 Code that iterates spreads and filters items by the page on which they lie using ISpread void FilterItemsByPage(UIDRef& documentUIDRef) { InterfacePtr<IDocument> document(documentUIDRef, UseDefaultIID()); InterfacePtr<ISpreadList> spreadList(document, UseDefaultIID()); IDataBase* database = documentUIDRef.GetDataBase(); int32 spreadCount = spreadList->GetSpreadCount(); for ( int32 spreadIndex = 0; spreadIndex < spreadCount; spreadIndex++ ) { UIDRef spreadUIDRef(database, spreadList->GetNthSpreadUID(spreadIndex)); InterfacePtr<ISpread> spread(spreadUIDRef, UseDefaultIID()); for (int32 pageIndex = 0; pageIndex < spread->GetNumPages(); pageIndex++) { UIDList itemsOnPage(database); const bool16 bIncludePage = kFalse; const bool16 bIncludePasteboard = kFalse; spread->GetItemsOnPage(pageIndex, &itemsOnPage, bIncludePage, bIncludePasteboard); // Add code to manipulate itemsOnPage. } } } The SnpInspectLayoutModel code snippet can inspect the spreads in a document and their associated hierarchy. Run the snippet in SnippetRunner to create a textual report. For sample code, see SnpInspectLayoutModel::ReportDocumentByHierarchy. Layers Layers are presented to the user and edited with the Layers panel. Layers can be shown or hidden, locked or unlocked. By re-arranging the order of layers, the user can control the front-toback order in which page items assigned to those layers draw. The user also can change the layer to which a selected page item is assigned, by dragging and dropping in the Layers panel. Figure 50 shows the user’s perspective of a layer. The document shown is a facing-pages document with one spread, one page, and one layer. Layout Fundamentals 161 Layout Fundamentals Layers FIGURE 50 User’s perspective of a layer Spread Page Layer Layers in a basic document Figure 51 is an object diagram showing the layout hierarchy that results when a new layer is added to the document in Figure 49. The diagram shows a document (kDocBoss) containing one spread (kSpreadBoss), one page (kPageBoss) and three layers. Each layer is represented by one kDocumentLayerBoss object that has two corresponding kSpreadLayerBoss objects in each spread. The pages layer that stores the page (kPageBoss) is represented by the kDocumentLayerBoss object named “pages” and the kSpreadLayerBoss objects named “pages” and “private.” Layer 1 is represented by the objects layer1, layer1-content, and layer1-guides. Layer 2 is represented by the objects layer2, layer2-content, and layer2-guides. A graphic frame (kSplineItemBoss) and a ruler guide (kGuideItemBoss) are assigned to Layer 1. Layer 2 is empty. 162 Layout Fundamentals Layers FIGURE 51 Document with two layers «boss» layout-c : kDocBoss ISpreadList::GetNthSpreadUID(0) «boss» spread1 : kSpreadBoss ILayerList::QueryLayer(0) ILayerList::QueryLayer(1) «boss» pages : kDocumentLayerBoss ILayerList::QueryLayer(2) «boss» layer1 : kDocumentLayerBoss «boss» layer2 : kDocumentLayerBoss IHierarchy::QueryChild(5) IHierarchy::QueryChild(4) IHierarchy::QueryChild(0)IHierarchy::QueryChild(1)IHierarchy::QueryChild(2)IHierarchy::QueryChild(3) «boss» pages : kSpreadLayerBoss IHierarchy::QueryChild(0) «boss» page1 : kPageBoss «boss» private : kSpreadLayerBoss «boss» layer1-content : kSpreadLayerBoss «boss» layer2-content : kSpreadLayerBoss IHierarchy::QueryChild(0) «boss» graphic-frame : kSplineItemBoss «boss» layer1-guides : kSpreadLayerBoss «boss» layer2-guides : kSpreadLayerBoss IHierarchy::QueryChild(0) «boss» ruler-guide : kGuideItemBoss When a new layer is added, three new objects are created: z A new document layer is added to the layer list (ILayerList). This is the kDocumentLayerBoss object layer2. z Two corresponding spread layers are added to the spread. One new spread layer is added to contain paths, frames, or groups; the other new spread layer is added to contain ruler guides. These are the kSpreadLayerBoss objects layer2-content and layer2-guides. Figure 51 shows that when a document layer is created, two corresponding spread layers are added to each spread. When a document layer is deleted, its corresponding spread layers are removed from each spread. Document-layer edits are document-wide; i.e., they affect all spreads in a document. Content-spread layers are stored contiguously in the spread’s hierarchy (IHierarchy). Guidespread layers also are stored contiguously. For example, the layer1-content and layer2-content objects in Figure 51 are contiguous content-spread layers, and layer1-guides and layer2-guides are contiguous guide-spread layers. Layout Fundamentals 163 Layout Fundamentals Layers The order of content-spread layers and guide-spread layers as child objects of the spread’s hierarchy (IHierarchy) varies, depending on whether guides are being drawn in front or in back of content. Ruler guides are kept in a distinct spread layer, to allow them to be drawn in front of or behind other content, or even to turn them off completely, as determined by a preference setting. (See “Guides and grids” on page 180.) Figure 51 shows the order when guides are drawn in front of content. The corresponding index order is as follows: index[0] index[1] index[2] index[3] index[4] index[5] pages spread layer private spread layer layer1-content spread layer layer2-content spread layer layer1-guides spread layer layer2-guides spread layer If guides are drawn behind other content, the index order of spread layers in the spread’s hierarchy (IHierarchy) is as follows: index[0] index[1] index[2] index[3] index[4] index[5] NOTE: pages spread layer private spread layer layer1-guides spread layer layer2-guides spread layer layer1-content spread layer layer2-content spread layer Child-index order in IHierarchy defines z-order, the order in which objects on those spread layers (kSpreadLayerBoss) draw. The child with index 0 draws first (behind); the child wth index n-1, last (in front). The spread’s ISpread interface has methods that return the spread layer associated with a given document layer. (See “Navigating spread content using ISpread” on page 166.) The associations are calculated using the following algorithm. The indices of the pages-spread layer and private-spread layer are fixed: z Pages-spread layer IHierarchy child index = 0. z Private-spread layer IHierarchy child index = 1. Variable definitions: z i = index of document layer (kDocumentLayerBoss) in ILayerList whose associated spread layer (kSpreadlayerBoss) is wanted. z c = number of document layers in ILayerList. If guides are displayed in front of content, the following calculations are used: z Content-spread layer IHierarchy child index = i + 1. z Guide-spread layer IHierarchy child index = i + c. If guides are displayed behind content, the following calculations are used: 164 z Content-spread layer IHierarchy child index = i +c. z Guide-spread layer IHierarchy child index = i + 1. Layout Fundamentals Layers Layer options There are layer options that can be controlled via the Layers Options dialog. User can double click on a layer name in the Layers palette to bring up the Layer Options dialog, as shown in Figure 52. FIGURE 52 Layer Options dialog The attributes in the Layer Options dialog are managed by the IDocumentLayer interface, which is aggregated on the kDocumentLayerBoss. Table 25 lists some of the commands that can be used to modify layer options. TABLE 25 Layer Options-related commands Command Note kChangeLayerNameCmdBoss Changes the name of the layer. kIgnoreHiddenTextWrapCmd Boss Sets text-wrap options for a document layer. kLockGuideLayerCmdBoss Locks or unlocks a guide layer. A “locked” layer means nothing in that layer (only guides) can be selected. kLockLayerCmdBoss Locks or unlocks a layer. A “locked” layer means nothing in that layer can be selected. Layers are unlocked by default. kPrintLayerCmdBoss Sets the printability of the layer. A non-printable layer does not print or export. kSetLayerColorCmdBoss Changes the layer color. kShowGuideLayerCmdBoss Sets the guide visibility of the layer. An “invisible” layer is not displayed on the screen. kShowLayerCmdBoss Sets the visibility of the layer. An “invisible” layer is not displayed on the screen. Layout Fundamentals 165 Layout Fundamentals Layers Use the commands in Table 25 whenever possible to modify layer options. The SnpPrintDocument.cpp SDK snippet allows the user to select which layer to print. It uses kPrintLayerCmdBoss to set the printability for each layer. For more information, see the snippet source code. NOTE: A similar set of attributes also exists in the ISpreadLayer. “Layers in a basic document” on page 162 explains the relationship between IDocumentLayer and ISpreadLayer in a document. The ISpreadLayer interface primarily provides “getter” methods that forward the request for information to the corresponding IDocumentLayer interface Navigating spread content using ISpread “Layers in a basic document” on page 162 shows the content of a spread is stored on its IHierarchy interface. Locating content using IHierarchy can be laborious. Alternately, the ISpread interface makes it easy to examine the content of a spread, as shown in the object diagram in Figure 53. 166 Layout Fundamentals Layers FIGURE 53 Layout Fundamentals Spread layer navigation using ISpread 167 Layout Fundamentals Master spreads and master pages Figure 53 shows you can use the ISpread interface on a spread (kSpreadBoss) to find the guide or content spread layer associated with a document layer. (For more information, see ISpread::QueryLayer.) You also can discover which page items lie on a given page. (For more information, see ISpread::GetItemsOnPage.) Using ISpread to discover the content of a spread is much easier than using IHierarchy. When run on the document shown in Figure 53, the code in Example 21 visits the content of spread layer layer1-content if parameter wantGuideLayer is kFalse. The code visits the content of spread layer layer1-guides if parameter wantGuideLayer is kTrue. EXAMPLE 21 Code that iterates over spreads in a document, then iterates over document layers to visitiitems on the spread layer associated with each document layer void FilterItemsByLayer(UIDRef& documentUIDRef, bool16 wantGuideLayer) { InterfacePtr<IDocument> document(documentUIDRef, UseDefaultIID()); InterfacePtr<ISpreadList> spreadList(document, UseDefaultIID()); InterfacePtr<ILayerList> layerList(document, UseDefaultIID()); IDataBase* database = documentUIDRef.GetDataBase(); int32 spreadCount = spreadList->GetSpreadCount(); for ( int32 spreadIndex = 0; spreadIndex < spreadCount; spreadIndex++ ) { UIDRef spreadUIDRef(database, spreadList->GetNthSpreadUID(spreadIndex)); InterfacePtr<ISpread> spread(spreadUIDRef, UseDefaultIID()); int32 layerCount = layerList->GetCount(); // Skip the pages layer (layer 0). for (int32 layerIndex = 1; layerIndex < layerCount; layerIndex++) { IDocumentLayer* documentLayer = layerList->QueryLayer(layerIndex); int32 pPos; // Visit the content spread layer associated with the document layer // if wantGuideLayer is kFalse, the guide spread layer otherwise. InterfacePtr<ISpreadLayer> contentSpreadLayer ( spread->QueryLayer(documentLayer, &pPos, wantGuideLayer) ); InterfacePtr<IHierarchy> hierarchy(contentSpreadLayer, UseDefaultIID()); VisitChildren(hierarchy); } } } NOTE: For an implementation of VisitChildren, see Example 18. Master spreads and master pages A master spread is a special kind of spread that contains master pages. A master page is a page designed to contain background content for another page. When a page is based on a master page, the page items that lie on the master page also appear on the page. A master page elimi- 168 Layout Fundamentals Master spreads and master pages nates the need for repetitive page formatting and typically contains page numbers, headers and footers, and background pictures. The layout presentation is used to edit the content of master spreads. The Pages panel is used to arrange the pages in a master spread and assign a master page to a page. See Figure 54 for the user’s perspective on master spreads and master pages. The publication shown is a facing-pages document with a master spread containing two master pages. FIGURE 54 User’s perspective of master spreads and master pages Master spread Master page Master page Master spreads and master pages in a basic document A master spread (kMasterPagesBoss) is a special kind of spread; it extends the spread boss class (kSpreadBoss). The content of a master spread is organized the same way as a spread: each has a hierarchy (IHierarchy) with spread layers acting as parent objects for content. Compare the spread shown in Figure 49 to the master spread shown in Figure 55. The document (kDocBoss) shown contains a master spread (kMasterPagesBoss), with two pages (kPageBoss), and two paths (kSplineItemBoss) in the form of a square and a circle. NOTE: Layout Fundamentals Pages (kPageBoss) that are part of a master spread are master pages. This name clashes with the name of the master-spread boss class, kMasterPagesBoss, so the distinction between the two is worth repeating: a master page is a page (kPageBoss) owned by a master spread (kMasterPagesBoss). 169 Layout Fundamentals Master spreads and master pages FIGURE 55 Facing-pages master spread «boss» layout-e : kDocBoss IMasterSpreadList Master spread «boss» A-Master : kMasterPagesBoss IHierarchy «boss» A-Master-pages : kSpreadLayerBoss «boss» A-Master-private : kSpreadLayerBoss «boss» A-Master-layer1-content : kSpreadLayerBoss IHierarchy «boss» A-Master-layer1-guides : kSpreadLayerBoss IHierarchy Master pages «boss» master-page-1 : kPageBoss «boss» master-page-2 : kPageBoss «boss» square : kSplineItemBoss «boss» circle : kSplineItemBoss When a page is based on a master page, the page items that lie on the master page also appear on the page. When the master spread in Figure 55 is applied to page 1 of the facing-pages document in Figure 49, page items from the master page appear on page 1. The circle in the screenshot of page 1 in Figure 56 is an object from the master spread. Figure 56 is an object diagram showing a one-page document that has a master (A-Master) applied. The circle drawn on page 1 is an object inherited from the associated master page. The boss objects that represent the spread and the master spread it is based on are shown. The association between a page (kPageBoss) and its master page is implemented by the IMasterPage interface. The screenshot shows that filtering of the objects on the master spread is being performed. Objects that intersect the bounding box of the master page associated with the page are drawn, other objects on the master spread are filtered out. The circle is the only object from 170 Layout Fundamentals Master spreads and master pages the master spread to draw, because it is the only object that intersects the bounding box of the master page associated with page 1. FIGURE 56 Spread based on a master spread Page item inherited from master «boss» layout-e : kDocBoss ISpreadList Spread IMasterPage «boss» spread1 : kSpreadBoss «boss» pages : kSpreadLayerBoss «boss» private : kSpreadLayerBoss «boss» page1 : kPageBoss IMasterSpreadList «boss» layer1-content : kSpreadLayerBoss «boss» layer1-guides : kSpreadLayerBoss «boss» graphic-frame : kSplineItemBoss «boss» ruler-guide : kGuideItemBoss «boss» A-Master-pages : kSpreadLayerBoss «boss» master-page-1 : kPageBoss Master spread «boss» A-Master : kMasterPagesBoss «boss» A-Master-private : kSpreadLayerBoss «boss» master-page-2 : kPageBoss «boss» A-Master-layer1-content : kSpreadLayerBoss Master page «boss» square : kSplineItemBoss «boss» A-Master-layer1-guides : kSpreadLayerBoss «boss» circle : kSplineItemBoss When two new pages based on the master shown in Figure 55 are added to the document, the layout hierarchy is as shown in Figure 57. The object diagram shows the boss objects that represent three pages in a facing-pages document based on the same master spread. The circle and square objects drawn on pages 1, 2, and 3 come from the master. FIGURE 57 Two spreads based on a facing-pages master spread Page items inherited from master «boss» layout-f : kDocBoss ISpreadList «boss» spread1 : kSpreadBoss «boss» pages : kSpreadLayerBoss «boss» private : kSpreadLayerBoss «boss» page1 : kPageBoss Layout Fundamentals IMasterSpreadList IMasterPage «boss» spread2 : kSpreadBoss «boss» layer1-content : kSpreadLayerBoss «boss» layer1-guides : kSpreadLayerBoss «boss» graphic-frame : kSplineItemBoss «boss» ruler-guide : kGuideItemBoss «boss» pages : kSpreadLayerBoss «boss» page2 : kPageBoss «boss» page3 : kPageBoss «boss» private : kSpreadLayerBoss «boss» layer1-guides : kSpreadLayerBoss «boss» layer1-content : kSpreadLayerBoss «boss» A-Master-pages : kSpreadLayerBoss «boss» master-page-1 : kPageBoss «boss» master-page-2 : kPageBoss «boss» A-Master : kMasterPagesBoss «boss» A-Master-private : kSpreadLayerBoss «boss» A-Master-layer1-content : kSpreadLayerBoss «boss» square : kSplineItemBoss «boss» A-Master-layer1-guides : kSpreadLayerBoss «boss» circle : kSplineItemBoss 171 Layout Fundamentals Master spreads and master pages The master spread (kMasterPagesBoss) associated with a page (kPageBoss) is found by calling IMasterPage::GetMasterPageUID. The associated master page (kPageBoss) within that master spread is calculated by calling IMasterPage::GetMasterIndex. The calculation depends on the index position (0, 1, 2, ...) of the page within its spread and the document set-up. Given the result returned by IMasterPage::GetMasterIndex, ISpread::GetNthPageUID can be called to get a reference to the master page (kPageBoss), or ISpread::GetItemsOnPage can be called to calculate the objects on the master spread that intersect the bounding box of the master page. To base a page or set of pages on a master spread, process the kApplyMasterSpreadCmdBoss command. Master-page item overrides Page items from a master spread can be overridden. For example, to change the fill color of the circle on page 1 in the Figure 57, a master page item override is created. A record of the override is kept by the page (kPageBoss) in the IMasterOverrideList interface. Overrides to master-page items are applied programmatically with kOverrideMasterPageItemCmdBoss. Even when a master-page item is overridden, changes made to its counterpart on the master still can effect page items. An overridden page item continues to inherit all properties of its master counterpart that are not overridden. For example, if the only property that was overridden on page 1 is the fill color of the circle, modifying the position of the circle in the master causes the position of the circle to be updated on the pages based on that master (pages 1 and 3). The application of the initial fill-color override creates a copy of the circle (kSplineItemBoss) object on spread 1; a record of the override is kept in IMasterOverrideList on page 1. The circle on spread 1 is a controlled page item; the circle on the master spread is the controlling page item. Master page items maintain a list of controlled page items in the IControlledPageItems interface, which represents the page items for which overrides were made. An overridden master-page item on a spread maintains a reference to its controlling master-page item, in the IControllingPageItem interface. Basing one master page on another A master page can be based on another master page. The association is maintained by the IMasterPage interface as it is for a normal page (kPageBoss) owned by a spread (kSpreadBoss). For example, consider two masters, A and B, with different sets of page items. When you drag master A onto master B in the Pages panel, master B becomes based on master A. Master page items on master A appear on master B; however, the page items on master B inherited from master A remain owned by master A. If you alter the page items on master A, the change is inherited by master B. Master B can override page items from master A for individual properties, just as the master-page items on a spread can be overridden. 172 Layout Fundamentals Page items Page items A page item is a path, frame, group, picture, text frame, or page-item type that represents content the user creates and edits on a spread. For general information about the organization of page items in a spread, see “Spreads and pages” on page 157. Frames and paths A path represents a straight line, curved line, or closed shape like a rectangle, ellipse, or polygon. A path comprises one or more segments, each of which may be straight or curved. Each path is open (the default) or closed. Graphic attributes are properties that control how the path is formatted when drawn, like stroke weight and color. For more information about paths, see the “Paths” section of the “Graphics Fundamentals” chapter. A frame is simply a path that contains—or is designated to contain—other objects, like a graphic page item, text page item, or page item that represents another type of content. Frames and paths are represented by the same boss class, kSplineItemBoss. A path can become a frame, and a frame can become a path. The difference between a path and a frame is the state of the interfaces on kSplineItemBoss. A path is a kSplineItemBoss object that contains no children in its IHierarchy interface. A graphic frame is a kSplineItemBoss object that contains a graphic page item in its IHierarchy interface. (For more information about graphic page items, see the “Graphic Page Items” section of the “Graphics Fundamentals” chapter.) A text frame is a kSplineItemBoss object that contains a text page item (kMultiColumnItemBoss). (For more information on text page items, see the “Text” chapter.) Figure 58 shows a square path, an empty graphic frame, a graphic frame displaying a picture, an empty text frame, and a text frame containing text. The object diagram shows a square being used as a path and as a frame. Layout Fundamentals 173 Layout Fundamentals Page items FIGURE 58 Square used as a path and a frame Above: Square. Above: Empty graphic frame. Below: Representation as a spline, a path-based object. Any spline can be used as a frame. Below: Representation as a spline designated for graphics content. IGraphicFrameData:: IsGraphicFrame returns kTrue. «boss» spread1 : kSpreadBoss Above: Graphic frame displaying JPEG picture. Below: Representation as a spline containing an image in its IHierarchy interface. The content of the frame is clipped by the frame's path. Above: Empty text frame. Below: Representation as a spline containing a column controller in its IHierarchy interface that in turn contains a column. The story (not shown) associated with these objects is empty. Above: Text frame displaying text. Below: Representation is the same as the empty text frame. The difference is that the associated story (not shown) contains text. «boss» layer1-content : kSpreadLayerBoss IHierarchy «boss» square : kSplineItemBoss «boss» empty-graphic-frame : kSplineItemBoss «boss» graphic-frame : kSplineItemBoss «boss» empty-text-frame : kSplineItemBoss «boss» text-frame : kSplineItemBoss «boss» jpeg-picture : kImageItem «boss» column-controller : kMultiColumnItemBoss «boss» column-controller : kMultiColumnItemBoss «boss» column1 : kFrameItemBoss «boss» column1 : kFrameItemBoss The toolbox palette provides the user with several path-drawing tools. The Rectangle, Ellipse, Polygon, and Line tools create basic shapes. The Rectangle Frame, Ellipse Frame, and Polygon Frame tools create basic graphic-frame shapes. The Pen and Pencil tools create free-form shapes. When one of these tools is used to draw a path, a spline item (kSplineItemBoss) is created to represent the path. The IPathGeometry interface on kSplineItemBoss describes the points in the path. Other interfaces on kSplineItemBoss provide properties like stroke weight 174 Layout Fundamentals Page items and stroke color that control how the path is drawn. When a path is used as a frame, the content is clipped by the frame’s path. IGraphicFrameData is a frame’s signature interface. IGraphicFrameData stores data that distinguishes whether the boss object represents a frame or a path. IFrameType is an alternative signature interface. It provides an easy-to-use interface that indicates whether the object represents a path or a frame. Major interfaces on kSplineItemBoss, the boss class representing paths and frames, are shown in the class diagram in Figure 59 and summarized in Table 26. For more information on the interfaces noted and details of the other interfaces on kSplineItemBoss, see the API reference documentation. FIGURE 59 kSplineItemBoss IFrameType «boss» kSplineItemBoss IGeometry IGraphicFrameData ITransform IHierarchy IPathGeometry IShape TABLE 26 Key kSplineItemBoss interfaces Interface Note IFrameType Indicates whether the boss object is a path or frame. IGeometry Stores the bounding box of the boss object in inner coordinates. See “Bounding box and IGeometry” on page 190. IGraphicFrameData Stores whether the boss object is a graphic frame and provides other helper methods to determine the content of a frame. IHandleShape Draws selection handles on the boss object’s bounding box. These selection handles are used to move and resize the object. IHandleShape (IID_IPATHHANDLESH APE) Draws selection handles on the points in the boss object’s path. These selection handles are used to edit the path points. Layout Fundamentals 175 Layout Fundamentals Page items Interface Note IHierarchy Connects the boss object into a tree that represents a layout hierarchy. Provides mechanism to find parent and child objects and interfaces. The objects the boss object contains are the children of the IHierarchy interface. The object in which the boss object is contained is its parent. The child-index order in IHierarchy defines the z-order of child objects. See “Parent and child objects and IHierarchy” on page 155. IPageItemAdornmentList A list of adornments that the page item object may have. For details, see the “Graphics Fundamentals” chapter. IPathGeometry Stores the points in the boss object’s path in inner coordinates. The interface can describe multiple paths. IScrapItem Creates commands that can copy and paste the boss object. Different types of page items need to transfer different kinds of data. For example, a path transfers a description of its shape, and a text frame transfers text as well as a description of the frame. IShape Draws the boss object. ITransform Represents any transformation applied to the boss object (e.g., translation, rotation, scaling) in a transformation matrix (PMMatrix). See “Transformation and ITransform” on page 191. A frame can contain at most one child in its hierarchy (IHierarchy). The child boss object is the content of the frame. The child may be one of the following boss classes: kSplineItemBoss, kGroupItemBoss, a graphics page item (e.g., kImageItem, kSVGItem, kPlacedPDFItemBoss, and kEPSItem), a text page item (kMultiColumnItemBoss), or another content page item. NOTE: The child object can be a group (kGroupItemBoss). To put several objects in a frame, first group them. A frame can be owned by one parent using its hierarchy (IHierarchy) interface. Typically, a frame on a spread is owned by a spread layer (kSpreadLayerBoss), but a frame also can be owned by other boss objects. For example, a frame that is part of a group is owned by the kGroupItemBoss, a frame nested inside a frame is owned by a kSplineItemBoss, and an inline frame is owned by a kInlineBoss. Paths and frames are created programmatically using IPathUtils. For sample code, see SDKLayoutHelper::CreateRectangleGraphic, SDKLayoutHelper::CreateSplineGraphic, SDKLayoutHelper::CreateRectangleFrame, and SDKLayoutHelper::CreateTextFrame. The frame for a page item can be created when a file is placed. For sample code that can be used to examine the content of a frame, see Example 18. For sample code that can be used to discover frames in a document, see Example 19 and Example 20. 176 Layout Fundamentals Page items The SnpInspectLayoutModel code snippet can inspect the spreads in a document and their associated hierarchy, including their frames. To create a textual report, run the snippet in SnippetRunner. For sample code, see SnpInspectLayoutModel::ReportDocumentByHierarchy. Graphic page items A graphic page item represents a picture. Table 27 shows the boss classes that represent graphics-format files that are imported and placed in a document. Graphic page items are contained in frames (kSplineItemBoss) when placed on a spread. For more information, see “Graphic Page Items” in the “Graphics Fundamentals” chapter. TABLE 27 Graphic page-item boss classes Boss class Represented graphics format kDCSItemBoss DCS kEPSItem EPS kImageItem Raster image formats (e.g., TIFF, JPEG, PNG, GIF) kPICTItem PICT kPlacedPDFItemBoss PDF kSVGItem SVG kWMFItem WMF Text page items A text page item represents a visual container that displays text. Table 28 shows the boss classes that participate in the display of text. Text page items are contained in frames (kSplineItemBoss) when placed on a spread. For more information, see the “Text Fundamentals” chapter. TABLE 28 Text page-item boss classes Boss class Represents kFrameItemBoss Column kMultiColumnItemBoss Column controller Layout Fundamentals 177 Layout Fundamentals Page items Interactive page items An interactive page item represents an item in a multimedia format. Table 29 shows the boss classes that represent interactive page items. Interactive page items are contained in frames (kSplineItemBoss) when placed on a spread. TABLE 29 Interactive item boss classes Boss class Represents kMoviePageItemBoss Movie kPushButtonItemBoss Button kSoundPageItemBoss Audio Groups Grouping is a way to combine two or more objects so they can be worked with as a single object. The objects in a group move, transform, copy, and paste as a unit. Grouping boss objects results in the creation of a kGroupItemBoss to represent the group. The grouped objects become the children of the group in its IHierarchy interface. Unlike a frame, a group does not have a path that clips its content when drawn. The geometry and shape of the group is defined by the objects in the group. The object diagram in Figure 60 shows an example of how the internal representation changes when two objects are grouped. 178 Layout Fundamentals Page items FIGURE 60 Grouping of two kSplineItemBoss path objects Before grouping Above: The original circle and square paths. Below: The IHierarchy associations between the boss objects that represent these paths on a spread. After grouping «boss» spread1 : kSpreadBoss «boss» layer1-content : kSpreadLayerBoss Above: The circle and square combined in a group. Below: The new group boss object, kGroupItemBoss, and the changed IHierarchy associations. The circle and square become children of the group. «boss» spread1 : kSpreadBoss «boss» layer1-content : kSpreadLayerBoss IHierarchy «boss» circle : kSplineItemBoss «boss» square : kSplineItemBoss «boss» group1 : kGroupItemBoss IHierarchy «boss» circle : kSplineItemBoss «boss» square : kSplineItemBoss A group must contain at least two children in its IHierarchy. The only boss classes that can be part of a group are kSplineItemBoss and kGroupItemBoss. In other words, only frames, paths, and groups can be grouped. To put a graphic page item—such as an image (kImageItem)—into a group, that item must be contained in a frame (kSplineItemBoss). There is no signature interface on kGroupItemBoss that identifies a boss object uniquely as a group. To test for a group, call IPageItemTypeUtils::IsGroup. Objects are grouped using the kGroupCmdBoss command and ungrouped using the kUngroupCmdBoss command. Selected objects can be grouped and ungrouped using IGroupItemSuite. Abstract page items and kPageItemBoss The kPageItemBoss boss class is the abstract base class for page items. The kDrawablePageItemBoss boss class is the abstract base class for page items that can be selected and edited on a Layout Fundamentals 179 Layout Fundamentals Guides and grids spread. These abstract classes are subclassed and implemented by the set of page items that can be created and edited on a spread, such as kSplineItemBoss, kGroupItemBoss, and kImageItem. In general terms, a page item is any object that can participate in a hierarchy (IHierarchy). This perspective is valid and includes spreads (kSpreadBoss) and pages (kPageBoss) as page items. There is an alternative, more advanced definition of page item. To see all subclasses of kPageItemBoss, see the API reference documentation for kPageItemBoss. Guides and grids Guides and grids are used to align and position objects. Some, like ruler guides, can be dynamically created and changed. Others, like the margins of a page, are static properties of an object. Ruler guides A ruler guide is a horizontal or vertical guide line used to align and position objects on a spread. Ruler guides are represented by the kGuideItemBoss boss class and are a type of page item. Ruler guides are represented as page items, because ruler guides share many behaviors of page items. Ruler guides can be associated with a layer, moved around on a spread, and copied and pasted. The signature interface that identifies a boss object as a ruler guide is IGuideData, which stores the properties of the guide. There are two kinds of ruler guides: page guides span a specific page, and pasteboard guides span the pasteboard of a spread. Ruler guides are kept in their own spread layer (kSpreadLayerBoss) in the spread hierarchy (IHierarchy), so ruler guides can be drawn in front or back of other content or completely hidden. For a description of this organization, see “Layers” on page 161. Ruler guides are created by the kNewGuideCmdBoss command. They can be changed by the kMoveGuideRelativeCmdBoss, kMoveGuideAbsoluteCmdBoss, kSetGuideViewThresholdCmdBoss, kChangeGuideColorCmdBoss, kSetGuidesBackCmdBoss, kSetGuideOrientationCmdBoss, and kSetGuideFitToPageCmdBoss commands. Guide preferences are stored in the IGuidePrefs interface on the document workspace (kDocWorkspaceBoss). A distinct set of preferences that are inherited by new documents is maintained on the session workspace (kWorkspaceBoss). The kSetGuidePrefsCmdBoss command is used to manipulate these preferences. Margin and column guides Margin guides represent the margins of a page. Column guides represent columns on a page. Each page (kPageBoss) has its own margin and column settings stored in IMargins and IColumns interfaces, respectively. The margins for a page can be changed using kSetPageMarginsCmdBoss. The columns for a page can be changed using kSetPageColumnsCmdBoss and kSetColumnGutterCmdBoss. 180 Layout Fundamentals Guides and grids Document grid The document grid is a grid (like graph paper) across a spread, on which page items can be aligned. Grid preferences are stored in the IGridPrefs interface on the document workspace (kDocWorkspaceBoss). A distinct set of preferences that are inherited by new documents is maintained on the session workspace (kWorkspaceBoss). The kSetGridPrefsCmdBoss command is used to manipulate these preferences. Baseline grid The baseline grid is used to align the baseline of text across multiple columns on a spread. Baseline-grid preferences are stored in the IBaselineGridPrefs interface on a story (kTextStoryBoss), the document workspace (kDocWorkspaceBoss), and the session workspace (kWorkspaceBoss). When a new story is created, the preferences in the document workspace are inherited by the story. New documents inherit preferences from the session workspace. The kSetBaselineGridPrefsCmdBoss command is used to manipulate these preferences. Each story can override its baseline-grid preference settings. Snap If snapping is on, when the user drags an object within a certain distance of a guide or grid, the object’s position is snapped to the guide or grid. If snapping is off, an object can be moved freely. Snapping is implemented by interaction between three main objects: z The object on which other objects are being moved around; for example, a spread (kSpreadBoss). This object supports snapping by instantiating the ISnapTo interface. z An object that can be snapped onto, like a guide or grid. The snapping is performed by a snap-to service. The signature interface is ISnapToService, and the ServiceID is kSnapToService. z The object handling the user interaction. Normally, this is a tracker created by a tool of some sort. See the API reference documentation for the ITracker interface. Snap preferences are stored in the ISnapToPrefs interface on the document workspace (kDocWorkspaceBoss). A distinct set of preferences that are inherited by new documents is maintained on the session workspace (kWorkspaceBoss). The kSetSnapToPrefsCmdBoss command is used to manipulate these preferences. Layout Fundamentals 181 Layout Fundamentals Layout-related preferences Layout-related preferences The interfaces that store the major preference settings related to layout are summarized in Table 30. Unless noted otherwise, each interface is present on the session workspace (kWorkspaceBoss) and document workspace (kDocWorkspaceBoss). kWorkspaceBoss contains the settings inherited when a new document is created. kDocWorkspaceBoss contains the settings for the document. For more information about the interfaces and commands listed, see the API reference documentation. TABLE 30 Layout-related preferences Interface Mutator IAutoTextFramePrefs kSetAutoTextFramePrefsCmdBoss IBaselineGridPrefs kSetBaselineGridPrefsCmdBoss IColumnPrefs kSetColumnPrefsCmdBoss IDocStyleListMgr 182 Note Stores a list of InDesign document presets (kDocStyleBoss). The Save Preset button in the New Document dialog box saves entries into this list. Present only on the session workspace (kWorkspaceBoss). kDocAddStyleCmdBoss, kDocDeleteStyleCmdBoss, kDocEditStyleCmdBoss, kDocSetStyleNameCmdBoss, kSaveDocumentStyleDataCmdBoss, kDocSetDefaultStyleNameCmdBoss IFrameEdgePrefs kSetFrameEdgePrefsCmdBoss IGridPrefs kSetGridPrefsCmdBoss IGuidePrefs kSetGuidePrefsCmdBoss ILayerPrefs kSetLayerPrefsCmdBoss IMarginPrefs kSetMarginPrefsCmdBoss IPageLayoutPrefs Stores the default shuffling behavior preferences for pages (between spreads) when pages are added, deleted, or moved. kSetPageLayoutPrefsCmdBoss IPageSetupPrefs Stores the default set-up of an InDesign document (number of pages, page size, orientation, etc.). kSetPageSetupPrefsCmdBoss IPasteboardPrefs kSetPasteboardPrefsCmdBoss ISnapToPrefs kSetSnapToPrefsCmdBoss IZeroPointPrefs kSetZeroPointPrefCmdBoss Layout Fundamentals Coordinate systems Coordinate systems This section describes the coordinate spaces used by layout, and the arrangement of the layoutrelated interfaces that store geometric data. Coordinate systems define the geometrical location of objects in a document and the canvas on which drawing occurs. Coordinate systems determine the position, orientation, and size of the text, graphics, and images that appear on a page. InDesign uses two-dimensional graphics. Position is defined in terms of coordinates on a twodimensional surface (a Cartesian plane). A coordinate is a pair of real numbers, x and y, that locate a point horizontally and vertically within a two-dimensional coordinate space. A coordinate space is determined by the location of the origin, the orientation of the x and y axes, and the lengths of the units along each axis. InDesign defines several coordinate spaces in which the coordinates that specify objects are interpreted. The following sections describe these spaces and the relationships among them. Transformations among coordinate spaces are defined by transformation matrices, which can specify any linear mapping of two-dimensional coordinates, including translation, scaling, rotation, reflection, and skewing. Matrices are used to move from one coordinate space to another. The approach used by InDesign aligns with PostScript and Adobe PDF. for more information, see the Adobe PDF Reference (http://partners.adobe.com/public/developer/pdf/index_reference.html). Computer Graphics Principles and Practice (Foley, James D., et al., Addison-Wesley, 1990) also provides useful theory on two-dimensional geometrical transformation. Transformation matrices A transformation matrix specifies the relationship between two coordinate spaces as a linear mapping of one coordinate space to another. By modifying a transformation matrix, objects can be scaled, rotated, translated, or transformed in other ways. In InDesign, a transformation matrix is specified by six numbers in the form of a PMMatrix. In its most general form, this PMMatrix is denoted [a b c d e f]; it can represent any linear transformation from one coordinate system to another. The PMMatrix patterns that specify the most common transformations are as follows: z Translation is specified by [1 0 0 1 Tx Ty], where Tx and Ty are the distances to translate the origin of the coordinate system in the horizontal and vertical dimensions, respectively. z Scaling is specified by [Sx 0 0 Sy 0 0]. This scales the coordinates so one unit in the horizontal and vertical dimensions of the new coordinate system is the same size as Sx and Sy units, respectively, in the previous coordinate system. Layout Fundamentals 183 Layout Fundamentals Coordinate systems z Rotation is specified by [cos(A) sin(A) -sin(A) cos(A) 0 0], which has the effect of rotating the coordinate system axes by an angle A counterclockwise. z Skew is specified by [1 tan(A) tan(B) 1 0 0], which skews the x axis by angle A and the y axis by angle B. Pasteboard coordinate space The pasteboard coordinate space is the global coordinate system that encloses all objects in a document, as shown in Figure 61. FIGURE 61 Pasteboard coordinate space Xpasteboard Ypasteboard All objects in a layout can have their coordinates expressed in pasteboard coordinates. The origin is the center of the first spread. The x axis increases from left to right; the y axis decreases from up to down. The length along each axis is measured in the PostScript unit of points. For example, Figure 62 shows the pasteboard coordinates of the bounding boxes for the spreads and pages in a basic document. The figure shows the pasteboard coordinates of the bounding box of each spread and page in a facing-page document with letter-sized pages of width 612 points and height 792 points. All values shown are in PostScript points. 184 Layout Fundamentals Coordinate systems FIGURE 62 Pasteboard coordinates of spread and page bounding boxes -1224,-468 0,-396 612,-396 1224,-468 Xpasteboard -1224,468 -1224,504 -1224,1440 0,396 -612,576 -612,1368 612,396 0,576 0,1368 1224,468 1224,504 1224,1440 Ypasteboard The unit in which all measurements are stored in a document is the PostScript point. The unit in which measurements are shown in the user interface is controlled by a preference (see “Measurement units” on page 192). Inner coordinate space and parent coordinate space Each page item has its own coordinate system, known as its inner coordinate space. Each page item has an associated parent coordinate space. The inner coordinate space and its relationship with its parent coordinate space are defined by three interfaces: z IHierarchy defines the parent association. The parent coordinate space is the first ancestor boss object on IHierarchy that has an IGeometry interface. This may not be the boss object’s immediate parent. For example, many objects are owned by a spread layer (kSpreadLayerBoss). Spread layers are not geometrical objects; they do not have an IGeometry interface; therefore, the parent coordinate space for a boss object owned by a spread layer is the spread (kSpreadBoss). z IGeometry defines the bounding box, which implies the origin and orientation of the x and y axes. z ITransform defines the transformation matrix that maps from the inner coordinate space to the parent coordinate space. Figure 63 shows a square containing a rectangular child page item as an example of a parent page item. The inner coordinate system of the parent as defined by its IGeometry interface is shown. Layout Fundamentals 185 Layout Fundamentals Coordinate systems FIGURE 63 Parent coordinates -100,-100 100,-100 Parent xparent Child -100,100 100,100 yparent B. Inner coordinates of parent A. Parent and child page items In the A part of Figure 63, the parent is a square (kSplineItemBoss), 200 points wide. The child is a rectangle (kSplineItemBoss), 40 points wide and 30 points high. The square is used as a frame for the rectangle; this association is defined by the IHierarchy interface. The objects are shown on a document grid with a grid line every 100 points and subdivisions every 10 points. In the B part of Figure 63, the bounding box stored by the square’s IGeometry interface defines the origin of the object’s inner coordinate space and the orientation of its x and y axes. The coordinates of the bounding box of the square in its inner coordinate space are shown, together with the x and y axes these coordinates imply. For a parent object, this is known as the parent coordinate space. The IGeometry and ITransform interfaces on the child object express the coordinate system relationship to the parent. There is more than one way to arrange this data. In Figure 64, the child’s coordinate system (the rectangle) is coincident with the parent’s coordinate system (the square). FIGURE 64 Coincident inner coordinates and parent coordinates 30,40 70,40 30,70 70,70 yparent C. Inner coordinates of child 186 xparent xparent xchild ychild Transformation matrix [1 0 0 1 0 0] (the identity matrix) 30,40 70,40 30,70 70,70 yparent D. After transformation of C to parent Layout Fundamentals Coordinate systems In the C part of Figure 64, the rectangle has its own inner coordinate space. The bounding box stored by the rectangle’s IGeometry interface is shown. This bounding box defines the origin of the object’s inner coordinate space and the orientation of its x and y axes, labeled xchild and ychild. The transformation matrix defined by the rectangle’s ITransform interface maps the rectangle’s inner coordinate space (the child coordinate space) into the square’s coordinate space (the parent coordinate space). In the arrangement shown, the parent and child coordinate systems are coincident; therefore, the transformation matrix in ITransform is the identity matrix. In the D part of Figure 64, when the bounding box of the child (the rectangle) is transformed using the child’s transformation matrix to the parent coordinate space (the square), the coordinates are expressed in the parent coordinate space as shown. In the arrangement shown in Figure 65, the child coordinate space is not coincident with its parent coordinate space. Instead, the origin of the rectangle’s coordinate space is located at the rectangle’s center. FIGURE 65 Non-coincident Inner coordinates and parent coordinates xparent xparent -20,-15 -20,15 20,-15 xchild 20,15 ychild yparent E. Inner coordinates of child Transformation matrix [1 0 0 1 50 55] (translation Tx=50, Ty=55) 30,40 70,40 30,70 70,70 yparent F. After transformation of E to parent In the E part of Figure 65, the origin of the rectangle’s inner coordinate space is located at its center. The coordinates of the bounding box defined by the rectangle’s IGeometry interface, are shown together with the x and y axes these coordinates imply, labeled xchild and ychild. The transformation matrix defined by the child’s ITransform interface specifies the translation required to map to the parent coordinate space. In the F part of Figure 65, when the bounding box of the child (the rectangle) is transformed using the child’s transformation matrix to the parent coordinate space (the square), the coordinates are expressed in the parent coordinate space as shown. A comparison of Figure 64 and Figure 65 shows that, after transformation, the bounding box of the rectangle in its parent’s coordinate space is the same. NOTE: Layout Fundamentals To transform any point from inner coordinate space to any other coordinate space, the page item’s transformation matrix (ITransform) must be applied. For utilities to help with the calculations, see TransformUtils. 187 Layout Fundamentals Coordinate systems Tools like the Rectangle tool use a tracker (CPathCreationTracker) to create a path (kSplineItemBoss) whose coordinate system is coincident with their parent coordinate system as shown in Figure 64. Facades like IPathUtils often are used to create a path (kSplineItemBoss) arranged as shown in Figure 65. Spread coordinate space Spread coordinate space is the coordinate system of a spread (kSpreadBoss). Each spread has its own coordinate space, also known as the inner coordinate space for a spread. The origin of the spread coordinate space is the center of the spread. The parent coordinate space is pasteboard coordinate space. Unlike other page items, the parent of a spread is not defined by IHierarchy; the parent of a spread is fixed as the document (kDocBoss). See Figure 66. FIGURE 66 Spread coordinate space Xspread1 Yspread1 Xspread2 Yspread2 In spread coordinates, the bounding box of each spread is identical. It is returned by IGeometry::GetStrokeBoundingBox. The spread’s (kSpreadBoss) implementation of IGeometry determines the bounding box using the IPasteboard interface. The spread’s ITransform interface stores a transformation matrix that translates the spread coordinate space to pasteboard coordinate space. This matrix is a translation matrix [1 0 0 1 0 Ty], where Ty specifies the spread’s offset in the vertical dimension. Figure 67 shows the spread coordinates of the bounding box of each spread and page in a facing-page document with letter-sized pages 612 points wide and 792 points high. 188 Layout Fundamentals Coordinate systems FIGURE 67 Spread coordinates of spread and page bounding boxes in a basic document -1224,-468 0,-396 612,-396 1224,-468 Xspread1 -1224,468 -1224,-468 0,396 Yspread1 -612,-396 0,-396 -612,396 Yspread2 0,396 612,396 1224,468 1224,-468 Xspread2 -1224,468 1224,468 Page coordinate space Each page has its own coordinate space, also known as the inner coordinate space for a page (kPageBoss). The parent coordinate space for page coordinate space is spread coordinate space. The origin of page coordinate space is the top-left corner of the page. See Figure 68. FIGURE 68 Page coordinate space Xpage1 Ypage1 Xpage2 Ypage2 Layout Fundamentals 189 Layout Fundamentals Coordinate systems In page coordinates, the bounding box of each page (kPageBoss) in a document is identical. It is returned by IGeometry::GetStrokeBoundingBox. The page’s ITransform interface stores a transformation matrix that translates the page coordinate space to spread coordinate space. Figure 69 shows the page coordinates of the bounding box of each page in a facing-page document with letter-sized pages 612 points wide and 792 points high. FIGURE 69 Page coordinates of page bounding boxes in a basic document 0,0 Xpage1 612,0 Ypage1 0,792 0,0 Xpage2 612,792 612,0 Ypage2 0,792 612,792 Page-item coordinate space Each page item has its own coordinate space, known as its inner coordinate space. The page item’s bounding box is stored in interface IGeometry. The geometrical data stored in IGeometry and other data interfaces specific to the page item type are in the inner coordinate space of the page item. For example, the points that describe a path in interface IPathGeometry are stored in the inner coordinate space. A transformation matrix that transforms from inner coordinate space to parent coordinate space is stored in the ITransform interface. The parent coordinate system is defined by the IHierarchy interface. For more information, see “Inner coordinate space and parent coordinate space” on page 185. Bounding box and IGeometry The bounding box (IGeometry::GetStrokeBoundingBox) is the smallest rectangle (PMRect) that encloses a geometric page item: 190 z The bounding box of an image (kImageItem) encloses the pixels that define its raster data. z The bounding box of a group (kGroupItemBoss) is the union of the bounding boxes of the objects in the group. Layout Fundamentals Coordinate systems z The bounding box of a path (kSplineItemBoss) encloses all points in the path (IPathGeometry) and includes the effect of the properties that control how the path is stroked, such as stroke weight and corner style. z The bounding box of a page (kPageBoss) or spread (kSpreadBoss) encloses the objects that lie on it. For illustrations, see “Spread coordinate space” on page 188 and “Page coordinate space” on page 189. A page item stores the data that describes its geometry in its inner coordinate space. For example, the bounding box in IGeometry and the points that describe a path in interface IPathGeometry are stored in inner coordinate space (see “Inner coordinate space and parent coordinate space” on page 185). This stored data is independent of any transformation that may be in effect. Transformation (e.g., scaling and rotation) is described by the page item’s ITransform interface. The IGeometry::GetPathBoundingBox method gives the path bounding box, the bounding box of a path excluding the effects of adornments. NOTE: Paths (kSplineItemBoss) have path bounding boxes; page items of other types may not. The IShape::GetPaintedBBox method gives the painted bounding box, the bounding box of the page item including the effect of adornments. Table 31 lists some useful geometry-related APIs. TABLE 31 Useful geometry-related APIs API Note IGeometry Stores the bounding box of a page item. IGeometryFacade Positions and resizes page items. IGeometrySuite Positions and resizes objects currently selected. Transformation and ITransform A page item has its own coordinate space, its inner coordinate space. (See “Inner coordinate space and parent coordinate space” on page 185.) The coordinates of the points that describe the page item are stored in this inner coordinate space. A transformation matrix (PMMatrix) that maps from inner coordinate space to the parent coordinate space is stored in the ITransform interface. Scaling, rotation, and other transformations that may be in effect are represented in this matrix. Points in inner coordinate space are mapped to the parent coordinate space using the matrix obtained from ITransform::GetInnerToParentMatrix. There are useful functions in TransformUtils.h that help to get the transform matrix (InnerToParentMatrix) and perform transform calculations. For details, see the API reference documentation. For example, to calculate the bounding box of a page item in its parent coordinate space, get the bounding box from the page item (IGeometry::GetStrokeBoundingBox), and apply its transformation matrix (ITransform::GetInnerToParentMatrix). The calculated bounding box takes into account all scaling, rotation, and other transformations that are applied. The parent could Layout Fundamentals 191 Layout Fundamentals Coordinate systems be a group (kGroupItemBoss), frame (kSplineItemBoss), spread (kSpreadBoss), or other kind of page item. A transformation matrix can be inverted (PMMatrix::Invert) to create a matrix that performs the inverse transformation. For example, if you have a matrix that transforms from inner coordinate space to parent coordinate space (InnerToParentMatrix), the inverse matrix can be used to transform points from parent coordinate space to inner coordinate space. The matrix that transforms from inner coordinate space to pasteboard coordinate space is returned by ITransform::GetInnerToRootMatrix. To access it, we recommend you use a helper function, InnerToPasteboardMatrix. This code walks up the hierarchy (IHierarchy) and concatenates the transformation matrix (ITransform::GetInnerToParentMatrix) of each page item. The end result is a matrix that maps from the inner coordinates of the page item it started from into pasteboard coordinates. To compare the coordinates of two or more page items, the coordinates first should be transformed to a common coordinate space. The pasteboard coordinate space often is used for this purpose. When creating a path (kSplineItemBoss), it often is useful to specify its position in pasteboard coordinates. You often position new page items relative to an existing boss object, like a spread, page, or frame. For example, to determine a position relative to a page, you first need the IGeometry interface of the page (kPageBoss); then you can call InnerToPasteboard to transform points on that page into pasteboard coordinates. When you have the points described in pasteboard coordinates, you can use IPathUtils to create the path. Alternately, you can describe the points in the parent coordinate space as shown by the sample code in SnpCreateFrame and SDKLayoutHelper. Table 32 lists some useful transformation-related APIs. TABLE 32 Useful transformation-related APIs API Note ITransform Stores the page item’s transformation matrix. TransformUtils Utility functions for transform calculations. See methods like InnerToPasteboard and PasteboardToInner in TransformUtils.h. ITransformFacade Scale, rotate, skew, or move page items. ITransformSuite Scale, rotate, skew, or move objects currently selected. Measurement units The internal unit of measurement used by the application is PostScript points. All measurements in a document are stored in the internal measurement unit as PMReal values. The user can choose to work in other measurement units, like centimeters, inches, picas, or ciceros. The user’s preferred measurement unit is converted to and from the standard internal unit (PostScript points) at the boundary between the user interface and the document model. 192 Layout Fundamentals Coordinate systems Unit-of-measure service The conversion from a specific measurement unit to the internal measurement unit is performed by a unit-of-measure service. A unit-of-measure service is a boss class that aggregates the IUnitOfMeasure and IK2ServiceProvider interfaces. IUnitOfMeasure is the interface responsible for converting between the unit of measure and the internal unit of measure. IUnitOfMeasure also has methods for producing a formatted string representation from units and tokenizing a string to produce a formatted number from the string. The measurement units supported by the application can be extended. For more information, see “Custom unit-of-measure service” on page 203. Common unit-of-measure services include kPointsBoss, kInchesBoss, kInchesDecimalBoss, kMillimetersBoss, kPicasBoss, kCicerosBoss, and kCentimetersBoss. Measurement-unit preferences The user’s preferred measurement unit is stored in the IUnitOfMeasureSettings interface. The session workspace (kWorkspaceBoss) stores the measurement-unit preferences inherited by new documents. The document workspace (kDocWorkspaceBoss) stores the document’s preferences. The user changes these preferences by choosing Edit > Preferences > Units & Increments and using the resulting dialog box. To change these preferences programmatically, use the kSetMeasureUnitsCmdBoss command. Figure 70 is a class diagram of IUnitOfMeasureSettings. FIGURE 70 Measurement-unit preferences (IUnitOfMeasureSettings) kWorkspaceBoss kDocWorkspaceBoss IUnitOfMeasureSettings IUnitOfMeasureSettings The measurement system, IMeasurementSystem, is an interface aggregated on kSessionBoss that is used to help locate and use a unit-of-measure service. Unit-of-measure services can be referred to by either their ClassID or an index the measurement system assigns. The index assigned by the measurement system is used while referring to a unit of measure in memory, but this index should be converted to a ClassID when writing or reading from a stream. Figure 71 is a class diagram of IMeasurementSystem. FIGURE 71 Measurement system (IMeasurementSystem) kSessionBoss IMeasurementSystem Layout Fundamentals 193 Layout Fundamentals The layout presentation and view Geometrical data types The core geometrical data types are as follows: z PMPoint — (x, y) coordinates expressed as real (PMReal) numbers. z PMRect — Rectangle represented by points that designate the top-left and bottom-right corners. z PMMatrix — Two-dimensional transformation matrix that maps from one coordinate space to another. The core geometrical-collection data types are as follows: z PMPointList z PMRectCollection z PMMatrixCollection The layout presentation and view This section describes the objects that present the layout to the user and allow the content to be edited interactively. Layout presentation The layout of a document is presented within a layout presentation. A document has a layout presentation (kLayoutPresentationBoss) for each view of the publication’s layout. A layout presentation is implemented by kLayoutPresentationBoss and its associated widgets. The pages and spreads are presented by the layout view (kLayoutWidgetBoss). The general arrangement is shown in the class diagram in Figure 72. 194 Layout Fundamentals The layout presentation and view FIGURE 72 Layout presentation Layout presentation kLayoutPresentationBoss Horizontal ruler kHorzRulerWidgetBoss Zero point kZeroPointWidgetBoss Vertical ruler kVertRulerWidgetBoss A document can be presented in one or more presentation views. Layout presentations present pages and spreads. Layout view kLayoutWidgetBoss «boss» kDocBoss 1 0..* Note: Presentations returned by IPresentationList are not always layout presentations. Other types of presentation may be open on a document; e.g., story windows. The other widgets provided by the layout presentation have not been modelled; e.g., the widgets that control the magnification of the IPresentationList view, page navigation, and scrolling. «boss» kLayoutPresentationBoss 1 1 IDocumentPresentation IPanelControlData «boss» kLayoutGenericPanelBoss 1 1 IPanelControlData «boss» kLayoutPanelBoss 1 0..1 «boss» kZeroPointWidgetBoss Layout Fundamentals 0..* «boss» kVertRulerWidgetBoss 0..1 «boss» kHorzRulerWidgetBoss 1 IPanelControlData «boss» kLayoutWidgetBoss 195 Layout Fundamentals The layout presentation and view The application may have several layout presentations open at once, each displaying different documents or different views of the same document, as shown in the class diagram in Figure 73. The figure shows a screenshot of the application with three layout presentations open. The boss classes and interfaces required to discover the documents open under the current session also are also shown. Each document knows the windows that are open on it by means of the IPresentationList interface on kDocBoss. FIGURE 73 Multiple layout presentations To discover the layout presentations that are open, iterate the IPresentationList interface on each document. Documents opened by the current session can be discovered as shown. Layout presentation of a second document Layout presentations showing different views of the same document. «boss» kSessionBoss 1 1 ISession::QueryApplication «boss» kAppBoss 1 1 IApplication::QueryDocumentList «boss» kDocumentListBoss 1 0..* IDocumentList::GetNthDoc «boss» kDocBoss IDocument IPresentationList A document does not need to have a presentation view. Documents that do not have a presentation view can be edited programmatically. Sometimes this called editing a headless document. Layout view The layout view presents the layout of a document and is represented by the kLayoutWidgetBoss boss class. Documents can contain a variety of objects, like spreads, pages, frames, text, and graphics. The document stores these objects; the layout view displays them and allows them to be edited interactively. The layout view is part of a layout presentation (see Figure 72). 196 Layout Fundamentals The layout presentation and view Only the visible part of a document is presented in layout view. The layout presentation controls which part of a document is visible using magnification and page navigation widgets, etc. Other panels, like the Pages and Navigation panels, also may adjust the view. The layout view sometimes is known as the layout widget. The layout view causes the visible objects to draw by discovering the spreads that are visible and calling each spread to draw. The general arrangement is shown in the class diagram in Figure 74. FIGURE 74 Layout view and its associated document The layout widget draws the area within the red highlight. Interface ILayoutControlData provides access to the document being presented. Additionally ILayoutControlData provides access to the spread, page, and layer being edited. Spread Floor «boss» kLayoutWidgetBoss 1 1 ILayoutControlData «boss» kDocBoss 1 1..* ISpreadList «boss» kSpreadBoss The layout view uses its ILayoutControlData interface to get to its associated document. The ISpreadList interface on the document provides access to any particular spread. The IHierarchy interface can be used to access children of the spread. For reasons of efficiency, navigation of the layout hierarchy during a window draw is somewhat more selective than shown in Figure 74. Portions of spreads that are not visible in a window are not called to draw. The layout view also discriminates between redrawing an entire window and drawing only the region that changed. These two strategies mean page items are not guaranteed to be called to draw during every window draw. Current spread and active layer The current spread is the spread (kSpreadBoss) targeted for edit operations. Normally, new page items created by the tools that handle user actions in the layout view are created in the current spread. Each view (kLayoutWidgetBoss) stores a reference to its current spread in ILayoutControlData::GetSpreadRef. The current spread is set in the user interface by clicking on a Layout Fundamentals 197 Layout Fundamentals The layout presentation and view spread in the layout view. The tool that handles the click processes the kSetSpreadCmdBoss command. A reference to the current spread of the view that most recently edited the document (kDocBoss) is stored in the IPersistUIDData interface with PMIID IID_ICURRENTSPREAD. The active layer is the layer targeted for edit operations. New page items created by the tools that handle user actions in the layout view are assigned to the active layer. Each view (kLayoutWidgetBoss) has a reference to its active layer (kDocumentLayerBoss) given by ILayoutControlData::GetActiveDocLayerUID. The active layer is set in the user interface by clicking on a layer in the Layers panel, which then processes the kSetActiveLayerCmdBoss command. A reference to the active layer of the view that most recently edited the document can be found by calling ILayerUtils::QueryDocumentActiveLayer. When creating a page item programmatically, choose its parent boss object. Normally, this is a spread layer (kSpreadLayerBoss). If you have access to a layout view, ILayoutControlData::QueryActiveLayer returns the hierarchy of the spread layer to use. NOTE: The current page is not stored anywhere in a document (in contrast, the current spread and active layer are stored as described above). ILayoutControlData::GetPage returns the visible page. This is calculated by means of ILayoutUIUtils::GetVisiblePageUID, by finding the page whose center point is closest to the center of the layout view. Layout-presentation and layout-view coordinate spaces The relationship between layout-presentation coordinates and layout-view coordinates is relatively static and is described by the respective IControlView implementations. When the user hides the rulers, the layout-view coordinate space is coincident with the layout-presentation coordinate space. The relationship between pasteboard coordinates and layout-view coordinates is stored in the layout view’s IControlView interface. The layout view’s IControlView::GetContentToWindowTransform method returns the transform that maps from pasteboard coordinates to layout-view coordinates. See Figure 75. 198 Layout Fundamentals Key client APIs FIGURE 75 Layout-presentation and layout-view coordinate spaces X layoutpresentation X layoutwidget Xpasteboard Ypasteboard Y layout-widget Y layout-presentation As the user zooms and scrolls the view, the relationship between layout-view coordinates and pasteboard coordinates changes. The layout view (kLayoutWidgetBoss) has an IPanorama interface to track the scroll and zoom changes. The relationship between the pasteboard and layout-view coordinate systems is stored in the layout view’s IControlView interface. The layout view’s IControlView::GetContentToWindowTransform method returns the transform that maps from pasteboard coordinates to window coordinates. By using the known coordinate relationships in the layout hierarchy, a region described in a page item’s inner coordinate space can be mapped to the window coordinates. Global-screen coordinates can be converted to pasteboard coordinates using ILayoutUIUtils::ComputePasteboardPoint. Event handlers often return mouse locations in global-screen coordinates. Key client APIs This section summarizes the APIs provided to manipulate layout-related objects. For more information, see the API reference documentation. The layout view (kLayoutWidgetBoss) displays a document for editing and provides some important data interfaces, summarized in Table 33. The layout view can be obtained in several ways, one of which is calling ILayoutUIUtils::QueryFrontLayoutData. Layout Fundamentals 199 Layout Fundamentals Key client APIs TABLE 33 Layout user-interface APIs API Note ILayoutControlData Data interface that refers to the document being viewed and the spread, page, and layer currently selected ILayoutControlViewHelper Helper routines for performing page item hit-testing Table 34 summarizes the suite interfaces that manipulate layout-related objects that are selected. To obtain a suite, client code can query a selection manager interface (ISelectionManager) for the suite of interest. If the suite is available, its interface is returned; otherwise, a nil pointer is returned. For details of how to obtain the selection manager, see the “Selection” chapter of Learning the Adobe InDesign CS4 Architecture. Given a selection manager, you can call suite methods using code that follows this pattern: InterfacePtr<IGeometrySuite> suite(selectionManager,UseDefaultIID()); if (suite) suite->MethodName(); TABLE 34 Layout suites 200 API Description IAlignAndDistributeSuite Aligns and distributes objects that are selected. IArrangeSuite Brings forward, sends backward, or performs other zorder-related operations on objects that are selected. IFrameContentSuite Content-fitting operations and frame conversion operations on objects that are selected. IGeometrySuite Positions and resizes objects that are selected. IGroupItemSuite Groups and ungroups objects that are selected. IGuideDataSuite Manipulates the properties of guides that are selected. ILayerSuite Manipulates document layers. ILayoutHitTestSuite Hit-tests objects that are selected. ILayoutSelectionSuite Sets the page items that are selected. IMasterPageSuite Manipulates master page item overrides. IPageItemLockSuite Locks or unlocks objects that are selected. IPathOperationSuite Performs path operations of selected page items. IPathSelectionSuite Performs path selections. IReferencePointSuite Manipulates reference point. ITransformSuite Scales, rotates, skews, or moves objects that are currently selected. Layout Fundamentals Key client APIs There are many command boss classes related to layout, as summarized in “Commands that manipulate page items” on page 204. When possible, try to avoid to avoid processing low-level commands when possible; instead, look for a facade or utility, to see if there is a method that serves your purpose on one of these interfaces. Facades encapsulate parameterizing and processing the low-level commands. For example, to add an item to a page-item hierarchy, you could process kAddToHierarchyCmdBoss, but instead you should use IHierarchyUtils::AddToHierarchy, which provides a ready-made facade. The facades and utilities related to layout are listed in Table 35 and Table 36. These interfaces are aggregated on kUtilsBoss. The Utils smart pointer class makes it straightforward to acquire and call methods on these interfaces. You can call their methods by writing code that follows this pattern: Utils<IPathUtils>()->MethodName(...) TABLE 35 Layout facades and utilities API Description IGeometryFacade Positions and resizes page items. ITransformFacade Scales, rotates, skews, or moves page items. IPathUtils Creates and works with paths (kSplineItemBoss). IFrameContentUtils Helps work with text or graphic-frame content. IHierarchyUtils Adds and removes page items from a hierarchy (IHierarchy). IImageUtils Helper functions to get image information. ILayoutUIUtils Helper functions related to the layout user interface. Most of these are related to the active or front document. ILayoutUtils Helper functions related to layout. Most of these are related to pages or the page-item hierarchy. IMasterSpreadUtils Helper functions for master spreads and master page items. IPageItemUtils Page-item helper functions, like cache and change notifications. IPageItemTypeUtils Helps determine the type of a page item (e.g., path, frame, and image). IPasteboardUtils Helps determine the spread by location or gets the location of page items. IPathInfoUtils Helps get path information. IPathPointUtils Stores path points during path-point transformation. IPathUtils Creates and manipulates path page items. IRefPointUtils Utility interface for functions that compute reference points. Layout Fundamentals 201 Layout Fundamentals Extension patterns API Description ITransformUpdateUtils Helps determine values relative to the zero point. IValidateGeometryUtils Validates transformation data. TABLE 36 Layout helper classes API Note Arranger Brings to front, sends to back, and performs other z-orderrelated operations. See ArrangeUtils.h. TransformUtils Utility functions for transform calculations. See methods in TransformUtils.h, such as such as InnerToPasteboard and PasteboardToInner. Extension patterns This section summarizes the mechanisms a plug-in can use to extend the layout subsystem. New-page-item responder A new-page-item responder lets a plug-in receive notification when a new page item (e.g., frame, path, group, or image) is created by kNewPageItemCmdBoss. For the complete list of page item types, see “Page items” on page 173. A new-page-item responder often is used to detect the creation of a specific type of page item. For example, to detect the creation of a graphic frame, implement a new-page-item responder that gets a reference to the new page item (INewPISignalData::GetPageItem) and then checks whether it is a graphic frame (IPageItemTypeUtils::IsGraphicFrame). Another common use of a new-page-item responder is initializing a custom data interface on a page item from defaults. Consider the case where you defined a custom data interface and added this data interface to the document workspace (kDocWorkspaceBoss) to store default data. You also added this data interface to kDrawablePageItemBoss to store the settings per page item, and you want the default data to be inherited when new page items are created. In this case, you can implement a new-page-item responder that copies the data from defaults into the new page item. For an implementation of this pattern, see BasicPersistInterface. 202 Layout Fundamentals Extension patterns A new-page-item responder is a service provider characterized by the following: z The responder interface IResponder — The implementation can expect to be able to acquire an INewPISignalData interface from the signal manager (ISignalMgr) that it is passed. z The signature interface IK2ServiceProvider — The ServiceID must be of type kNewPISignalResponderService. You can re-use the API implementation kNewPISignalRespServiceImpl for this. Sample code BasicPersistInterface copies data from defaults into new page items. Custom page item A custom page item lets a plug-in extend the set of objects that can be laid out on a page. A custom page item gives the plug-in control of how the object is drawn and how it behaves when selected and manipulated by the user. A common use of a custom page item is adding support for a graphics format for which the application provides no native support. In this case, the custom page item also requires a custom import provider (IImportProvider), to allow files of that graphics format to be placed. Some custom page items also may require custom tools to be implemented to create and manipulate the custom page items. Implementing a custom page item can be complex. Before beginning development of a custom page item, evaluate whether another type of extension pattern—like a page-item adornment or draw-event handler—might meet your needs. If you do need to implement a custom page item, study the subclasses of kPageItemBoss to see if there is an existing page item that is a close match to what you need. (See kPageItemBoss in the API reference documentation.) If an existing page item comes close to meeting your needs, use this boss class as the base class for your implementation. The examples provided in the SDK show only the basics of what is involved. Sample code z BasicShape specializes kSplineItemBoss and shows how to implement the interfaces involved in drawing a page item. z CandleChart specializes kSplineItemBoss to show how to draw some data as a chart. Custom unit-of-measure service Plug-ins can extend the set of measurement units supported by the application by defining a unit-of-measure service. The following steps outline what a plug-in needs to do to make a custom unit of measure appear in the Edit > Preferences > Units & Increments dialog box: 1. Define a unit-of-measure service boss class. 2. Implement the C++ code for IUnitOfMeasure, using CUnitOfMeasure as a base. Layout Fundamentals 203 Layout Fundamentals Commands that manipulate page items 3. Implement IK2ServiceProvider using the default kUnitOfMeasureService provided by the API, which registers the custom unit with the application-measurement system. 4. Include a ruler-resource description of the ODFRez type RulerDataType for your custom unit of measure in the .fr resource file. Rulers Rulers are displayed by the ruler widgets (kHorzRulerWidgetBoss and kVertRulerWidgetBoss). The presentation of the ruler is described by the data defined in the ODFRez resource type, RulerDataType. This type describes the font, associated unit-of-measure service ClassID, and tick-mark layout. For more details, see RulerType.fh. Typically, a ruler is associated with a particular unit-of-measure service. The resource description for the ruler is in the same plug-in as the unit-of-measure service. The unit-of-measure service returns the resource ID of its ruler description in its implementation of IUnitOfMeasure::GetRulerSpecRsrcSpec. When a new view is created on a document, the preferred measurement unit is determined. Then, the associated unit-of-measure service is queried for the resource ID of its ruler description. If one exists, that description is used to create a new ruler as part of the new view of the document. Sample code CustomUnits creates a custom unit. In addition, it provides a resource description of how the ruler tick markers are specified for the custom units. CstUniRuler.fr from the sample shows a sample ruler resource. Commands that manipulate page items Page-item creation commands TABLE 37 Commands that create page items 204 Command Description kCreateMultiColumnItemCmdB oss Creates a new text frame. kImportAndLoadPlaceGunCmd Boss Combination of kImportPIFromFileCmdBoss and kLoadPlaceGunCmdBoss. kImportAndPlaceCmdBoss Combination of kImportPIFromFileCmdBoss and kPlacePICmdBoss. Layout Fundamentals Commands that manipulate page items Command Description kImportPIFromFileCmdBoss First, this command imports a file. If what is imported is a story, a multicolumn item is created. If what is imported is not in a graphic frame, a new graphic frame is created and the imported file is put into the frame. The UID of the new item is returned on the command’s item list. kLoadPlaceGunCmdBoss Loads the item specified on the command’s item list into the place gun. Only one item can be loaded by this command. kNewPageItemCmdBoss Used to create a new page item. You will need to use this command only if you are creating a custom page item. Do not use this command to create a pageitem type supplied by the API, a kSplineItemBoss, kImageItem, or kMultiColumnItemBoss. Each page-item type provides a command to create it. The newly created page item can be any simple page item that supports the IGeometry interface. All attributes for the new page item are stored in the INewPageItemCmdData interface. The UID of the new page item is returned in the command’s item list. If the parent is supplied, the new page item is added to the hierarchy. kPlaceGraphicFrameCmdBoss Creates a graphic frame and places an image item into it. The item to be placed can be passed through the command’s item list or placed from the place gun. To use the place gun, set the usePlaceGunContents parameter on the IPlacePIData interface to kTrue, and do not set the command's item list. When passing the UID of the placed item using the command's item list, set the usePlaceGunContents parameter to kFalse. kPlaceItemInGraphicFrameCmd Boss Places a page item into an existing graphic frame. The page item can be passed into the command’s item list, or it can be placed from the place gun. The UID of the graphic frame is returned on the command’s item list. kPlacePICmdBoss Places a page item. This command does not create a new page item. It command takes an existing page item from the command’s item list or the place gun, then places the page item into the page item hierarchy. kReplaceCmdBoss Replaces one page item with another. Both the old page item and the new page item are specified in the IReplaceCmdData interface. Page-item update commands TABLE 38 Commands that add/remove a page item to/from a hierarchy Command Description kAddToHierarchyCmdBoss Adds the page item in the command’s item list to the parent specified in the IHierarchyCmdData interface. The index position for the page item also is specified on the IHierarchyCmdData interface. For example, when a new page item is created, it calls this command if the new item’s parent was supplied. kRemoveFromHierarchyCmdBoss Removes a page item from its parent when deleting a page item or detaching the imported content from the imported frame. Layout Fundamentals 205 Layout Fundamentals Commands that manipulate page items TABLE 39 Commands that position page items Command Description kAlignCmdBoss Aligns the page items in the command’s item list to the alignment type specified in the IIntData interface. The command itself is a compound command made up of a set of move-relative commands. Since the move commands are undoable, the align command also is undoable. kCenterItemsInViewCmdBoss Moves a set of page items so they appear centered in the current view. This command is not undoable. kFitPageItemInWindowCmdBoss Used to make the current selected page items fit in a window. This command is not undoable. kMoveToLayerCmdBoss Moves the page items specified on the command’s item list to the document layer specified on the IUIDData interface. The page items appear in the same z-order relative to each other as before in front of the new layer. This command does not move the items that are children of a group or a graphic frame, nor does it move standoffs. kMoveToSpreadCmdBoss Like kMoveToLayerCmdBoss, except kMoveToSpreadCmdBoss moves the page items from one spread to another. TABLE 40 Commands for content fitting Command Description kAlignContentInFrameCmdBoss Aligns the contents in the command’s item list to the specified corners of their respective frames. The corner, which is the same for all items, is specified on the IAlignContentInFrameCmdData interface. This command ignores frames without content. The command’s item list holds the UIDs of the contents, not the UIDs of the frames that contain the contents. This command sends out a notification that the content’s subject has changed. kCenterContentInFrameCmdBoss Positions the contents at the centers of their respective frames. The content UIDs are stored in the command’s item list. kFitContentPropCmdBoss Takes a list of frame content and modifies the content size and transformation to fit the frames and maintain the content’s proportions. kFitFrameToContentCmdBoss Resizes each frame in the command’s item list to fit its content’s path bounding box. This command takes a list of page items, filters out the empty frame and non-graphical frame, and transforms the frame's path geometry. The text frames are still in the command’s item list, even though they are not affected by this and other commands. NOTE: 206 Sometimes, after replace or paste operations, the graphic frame content (e.g., the placed image, PDF, or EPS item) does not fit into the frame or is not at the position you want inside the frame. Unfortunately, there is no graphic attribute or helper function that can determine the fitting mode for a page item. You can compare the bounding boxes for the content (for example, the image item) and the parent (the frame), to decide whether Layout Fundamentals Commands that manipulate page items the content should be positioned in the center, fit into the frame, or aligned to the corner of the frame using a content-fitting command. Because these commands are one-time actions and not attributes, however, these commands must be executed again if the page items are resized. TABLE 41 Commands that designate the type of a frame Command Description kConvertFrameToItemCmdBoss Takes a list of graphic frames and text frames with no content and converts them to graphic items (unassigned), which are neither text frames nor graphic frames. This command sets the graphic-frame attribute of the specified page items to kFalse. kConvertItemToFrameCmdBoss The opposite of kConvertFrameToItemCmdBoss. kConvertItemToFrameCmdBoss sets the graphic-frame attribute of the specified page items to kTrue and converts unassigned graphic items to graphic frames. It command also converts empty text frames to empty graphic frames. kConvertItemToTextCmdBoss Converts unassigned page items and empty graphic frames to empty text frames. TABLE 42 Commands that copy and paste page items Command Description kCopyCmdBoss A generic command for copying page items from one document to another. This command applies to any page item that supports the IScrapItem interface. kCopyImageItemCmdBoss Copies the specified image item to the specified target. Both the image item and the target are specified in the ICopyCmdData interface. kCopyPageItemCmdBoss Copies one or more page items to the specified parent object, if any. A UIDList of the page items created is returned in the command’s item list. kDuplicateCmdBoss Duplicates the items specified in the command’s item list. The page items in the command's item list are duplicated if the command is prepared successfully. kPasteCmdBoss Pastes one or more page items to the specified database in the command’s ICopyCmdData interface. The UIDList of the items to paste are passed to the command in the ICopyCmdData interface. kPasteGraphicItemCmdBoss Used for pasting EPS, image, and PDF items into the destination database. The difference between kPasteGraphicItemCmdBoss and kCopyPageItemCmdBoss is that if the specified parent is a graphic frame, the graphic item (EPS, image, PDF) is created as a child of the frame. If no frame is specified as the parent, kPasteGraphicItemCmdBoss creates a new rectangular frame as its parent and applies all its transformation values to the frame, so it appears in the correct location. kPasteInsideCmdBoss Pastes the specified content into a frame and, if necessary, deletes previous content. The pasted content is aligned to the top left. Layout Fundamentals 207 Layout Fundamentals Commands that manipulate page items TABLE 43 Commands that transform page items Command Description kTransformPageItemsCmd Boss Performs various page-item transformations, such as move, rotate, scale, and skew. The caller needs to pass in appropriate data. kTransformPathPointsCmd Boss Transforms path points of page items. The transformation could be move, rotate, scale, skew, etc. The caller needs to pass in appropriate data. NOTE: We strongly recommend using ITransformFacade and ITransformSuite for your transformation needs. Although other transform commands are still available, they may be removed in the future, so we strongly recommend you use only the two commands in Table 43. TABLE 44 Commands that group page items NOTE: Command Description kGroupCmdBoss Groups selected items in the list and creates a new page item consisting of the group. The parent for the group is the same as the parent of the last item in the sorted selected-item list. The UID of the new group page item is returned in the command’s item list. This command requires that the items to be grouped have valid parents, because only items at the same level in the hierarchy can form a group. For example, it is invalid to try to group an image with the spline item that contains it (or any other splines not at the same level as the image of the document hierarchy). kUngroupCmdBoss Ungroups the items specified in the command’s item list. The parent of the group becomes the parent of all ungrouped items. TABLE 45 Commands that lock page items 208 Command Description kSetLockPositionCmdBoss Used to lock/unlock the page items. (See the ILockPosition interface.) Layout Fundamentals Commands that manipulate page items Page-item deletion commands TABLE 46 Commands that delete page items Command Description kDeleteCmdBoss Deletes the page items specified in the command’s item list. Any groups left empty by the deletions also are deleted. kDeleteFrameCmdBoss Deletes both the frame and its contents. In general, you should avoid directly calling this command. Instead, use the GetDeleteCmd method of the IScrapItem interface to delete the frame. kDeletePageItemCmdBoss Deletes the page items specified in the command’s item list and removes the items from the hierarchy. In general, you should avoid directly calling this command. Instead, use the GetDeleteCmd method of the IScrapItem interface to delete the page item. kDeleteImageItemCmdBoss kDeleteImageItemCmdBoss is a subclass of kDeletePageItemCmdBoss. The purpose of kDeleteImageItemCmdBoss is to release an image object when the page item is deleted. This command deletes the image items on the command’s item list. If the ClassID of any item is not kImageItem, that item is not deleted. kDeleteLayerCmdBoss Deletes the layer specified on the command’s item list. The layers in the item list must be in the same document. After this operation, all page items on the layer list also are deleted. kDeletePageCmdBoss Deletes the pages specified on the command’s item list. Page items on the pages also are deleted. If the spread is left without pages by this command, the spread also is deleted. If page reshuffling is specified on the IBoolData interface, the remaining pages in the affected spread and pages in the spreads that follow are reallocated so each spread has the number of pages specified in the page set-up preferences for the document. kDeleteSpreadCmdBoss Deletes one or more spreads and all their pages and page items. If the deletion would leave the document without spreads, the command is aborted and nothing is deleted. The list of spreads to delete is specified in the command’s item list. kDeleteUIDsCmdBoss Deletes the UIDs specified on the command’s item list. kRemoveInternalCmdBoss Used when you delete a page item with embedded data. This command removes the embedded data from the publication. Layout Fundamentals 209 Layout Fundamentals Commands that manipulate page items 210 Graphics Fundamentals Paths Graphics Fundamentals This chapter explains how the appearance of page items is specified, how page items are drawn, and how you can customize how page items are drawn. The objectives of this chapter are as follows: z Show how paths are defined and manipulated. z Illustrate graphic page-item structure and how to import and export graphics files. z Examine how colors and related properties of graphics are represented. z Introduce graphic attributes. z Describe stroke-related effects, like custom path strokers. z Introduce transparency and transparency effects. z Outline how spreads and page items are drawn to the screen and printed. z Describe extension patterns to let you customize how page items are drawn. For definitions of terms, see the “Glossary.” Paths This section shows how a path is defined and drawn according to its control points. Path concepts Paths Paths can be created using various tools in InDesign. Shape tools and Frame tools create closed paths, the Pencil tool creates continuous smooth paths with lots of anchor points, and the Pen tool allows you create paths with great precision. A path page item may have one or more paths. For example, a line, a rectangle, or an oval consists of one path; a compound path, two or more paths. Path points A path is defined by its path points. A path may have one or more path points. Path points are represented by PMPathPoint objects. There are three types of path points: z kL, line point — Used to form a straight line. These (and kCK path points) are called corner points. z kCS, continuous smooth point — Used to form a continuous smooth curve. These are called smooth points. z kCK, continuous unsmooth point — The point’s left and right tangents are not on the same line. These (and kL path points) are called corner points. Graphics Fundamentals 211 Graphics Fundamentals Paths A PMPathPoint object stores three PMPoint objects, represented as pairs of (x,y) coordinates. These PMPoint objects represent the anchor point, the left-direction point, and the right-direction point, respectively (see Figure 77). For a kL path point, the left- and right-direction points are the same as the anchor point. Figure 76 shows examples of path points. In part A, the line consists of two kL points. In part B, the middle kCK point has two direction points that are not on a line with the anchor point. In part, the middle kCS point’s anchor point and two direction points form a line. FIGURE 76 Path-point types Path drawing A path is controlled by its path points. InDesign draws Bezier curves based on the path points. Figure 77 shows an open path with six path points. FIGURE 77 Path with six path points D th ep of v e r cu 212 Graphics Fundamentals Paths In the figure, note the following: z Every anchor point (1, 2, 3, 4, 5, and 6) is on the path. z Points 21, 31, 41, 51, and 61 are left-direction points. Points 22, 32, 42, 52, and 62 are rightdirection points. z Direction lines (from anchor point to direction point) always are tangent to (perpendicular to the radius of) the curve at the anchor points. z The angle of each direction line determines the slope of the curve, and the length of each direction line determines the height, or depth, of the curve. z A path is drawn segment by segment. The shape of each segment is determined by its two end anchor points and their direction points. For example, curve (1,2) is determined by anchor points 1 and 2 and left-direction point 21; curve (2,3) is determined by anchor points 2 and 3, right-direction point 22, and left-direction point 31. If a path is closed, the last segment is controlled by the last and first path points. For more details, see PMBezierCurve.h. Winding rule The winding rule determines whether a given point is inside or outside the area defined by a path. InDesign supports both even-odd and non-zero winding rules: z Even-odd winding rule — If a ray drawn from a point in any direction crosses the path an odd number of times, the point is inside; otherwise, the point is outside. z Non-zero winding rule — The crossing count for a ray is the total number of times the ray crosses a left-to-right portion of the path minus the total number of times the ray crosses a right-to-left portion of the path. If a ray drawn from a point in any direction has a crossing count of zero, the point is outside; otherwise, the point is inside. For details, see the book PostScript Language Reference, available on the Adobe Web site. The winding rule of an object is stored as a graphic attribute of the kGraphicStyleEvenOddAttrBoss page item; therefore, you can get or set the winding rules through IGraphicsAttributeUtils the same way as other graphic attributes. For more information, see “Graphic attributes” on page 256. Paths data model Path page-item structure Paths can exist on any page item that defines an IPathGeometry interface. Figure 78 show the relationship among page item, path, path point, and point. A path can be viewed as connected path segments or connected path points. Graphics Fundamentals 213 Graphics Fundamentals Paths FIGURE 78 Path page-item structure A page item has at least one path associated with it. This package includes all ancestors of a page item. See details in "Layout fundamentals" for information on navigating to page items. Document hierarchy 1owns 1..* A path consists of straight or curved line segments. IPathGeometry Path page item 1owns 1..* owns Path A path point defines an anchor point and the directions of the path at the anchor point. 1 1 owns 0..* Path segment 1..* 2 1 defined by Path point 1 owns A point mathematically defines coordinates of a position. 3 A path segment connects two path points. Point Path geometry There is no object in the InDesign object model that maps to a single path directly; instead, all path points of all paths of a page item are stored using the interface defined by the IPathGeometry class. IPathGeometry is the signature interface of a path page item. It has methods to access path information of a page item, like the number of paths the page item has and whether a path is open or closed. Paths are differentiated using a path index. Methods for accessing path points normally require a path index parameter. The PMPathPointList type is defined as K2Vector<PMPathPoint>. An item of this type stores a list of path points; for example, all path points of a path. Unlike with IPathGeometry, path points stored in an item of type PMPathPointList are not divided into paths by path index. The most common path page item is the spline item, represented by kSplineItemBoss. Spline items include paths (lines, curves, frames) like those shown in Figure 76 and Figure 77. There 214 Graphics Fundamentals Paths are several other kinds of paths, including image-clipping paths, text-wrap paths, and text outlines. All paths use IPathGeometry to store paths. Path operations You can access paths of a page item through the interface defined by the IPathGeometry class. InDesign also encapsulates some complex manipulations into several high-level path operations, which are provided as commands and selection suites. Compound paths You can combine two or more paths, compound paths, grouped page items, text outlines, text frames, or other shapes that interact with and intercept one another to create a new compound path. The advantage of a compound path over individual paths is that a compound path is a single object, so you can apply attributes to the compound path as a whole. Use kMakeCompoundPathCmdBoss to create a new compound path and kReleasePathsCmdBoss to split a compound path into individual paths. NOTE: A compound path does not connect or join any two points of existing paths; it only puts two paths together in one page item. Comparing compound paths and groups Both compound paths and groups involve combining multiple page items as a whole. The main difference between compound paths and groups is that making compound paths combines all items together into one page item (all other original page items are deleted), whereas grouping does not delete the original page items; they are just moved into the new group item. See Figure 79. The steps in the figure are explained below. FIGURE 79 Compound path contrasted with group (1) original red rectangle and yellow oval Graphics Fundamentals (2) result of compound path (3) result of group with 50% opacity applied 215 Graphics Fundamentals Paths In Figure 79: 1. The original page items are a red rectangle and a yellow oval, represented by kSplineItemBoss object A and kSplineItemBoss object B, respectively. 2. To make a compound path out of these two objects, to take the path points from kSplineItemBoss object B and add them to kSplineItemBoss object A through the IPathGeometry interface, then delete kSplineItemBoss object B. The result is only one kSplineItemBoss object, A, with new path points. The new item retains the first item’s graphic attributes, including fill color. All path operations use the even-odd winding rule, resulting in the hole in the compound path. 3. To group the two page items instead, InDesign first creates a kGroupItemBoss object, then removes both kSplineItemBoss object A and kSplineItemBoss object B from their current hierarchical parents and adds them as hierarchical children to kGroupItemBoss. The result is three different boss objects. The graphic attributes of the original items are retained. You can apply graphic attributes to a group page item or its children independently. Path-finder operations Path-finder operations, also referred to as compound-shape operations, combine shapes enclosed by the paths. InDesign supports adding, subtracting, intersecting, excluding-overlap, and minus-back operations. Figure 80 illustrates the results of these path finder operations. FIGURE 80 Path-finder operations (1) original red rectangle and yellow oval (4) result of path finder subtract operation (2) result of path finder add operation (3) result of path finder intersect operation (5) result of path finder exclude overlap operation (6) result of path finder minus back operation You can use kMergePathCmdBoss or IPathOperationSuite to achieve the effect. Path-finder operations require exactly two input objects. The attributes of the front object are retained by the result object, except in the case of the subtract operation. 216 Graphics Fundamentals Graphic page items Shape conversion Shape conversion changes the current shape to a new shape. InDesign can convert to various shapes, including lines, triangles, rectangles with corner effects, ovals, and polygons. Figure 81 shows the result of converting a rectangle and an oval to inverse-rounded rectangles. FIGURE 81 Convert shape (1) original red rectangle and yellow oval (2) result of converting shape to inverserounded rectangle The command to achieve this effect is kConvertShapeCmdBoss. It gets the bounding box of the current shape, then inserts or changes path points in the IPathGeometry object to represent the desired shape, so the resulting page item maintains the same bounding box as the original shape. IConvertShapeSuite takes shape type, corner effects, and several other parameters. You can use this method to convert a shape to a new shape with a new combination of attributes, like shape type, corner effects, and number of polygon sides. NOTE: If you convert a page item from shape A to shape B, then convert from shape B back to shape A again, the number of path points and their coordinates may be different than for your original shape A. Graphic page items This section discusses the concepts and data model for graphic page items, as well as graphic page-item special operations, like setting clipping paths and text-wrap contours. This section also covers importing and exporting graphics files. Graphic page-item types Computer graphics fall into two main categories, vector graphics and raster images. InDesign can import raster images, vector graphics, or a combination of both, depending on the graphics-file format. Graphics Fundamentals 217 Graphics Fundamentals Graphic page items Raster images Raster images, or bitmap images, are the most common electronic medium for such continuous-tone images as photographs or images created in painting programs like Adobe Photoshop®. Raster images are resolution dependent. InDesign supports almost all popular raster-image formats, including PSD, JPEG, TIFF, GIF, PNG, BMP, and Scitex, all of which are represented by kImageItem boss, which is discussed in more detail in “Graphic page-item boss-class inheritances” on page 223. An alpha channel is an invisible channel that defines transparent areas of a graphic. The alpha channel is stored in a graphic with the RGB or CMYK channels. A user can create alpha channels using background-removal features in Photoshop. Vector graphics Vector graphics use geometrical formulas to represent images. Paths created using the drawing tools in the InDesign Toolbox are examples of vector graphics. Vector graphics are more flexible than bitmaps, because vector graphics can be resized without losing resolution. Another advantage of vector graphics is that their representations often require less memory than representations of bitmap images. NOTE: Since most output devices are raster devices, vector objects must be translated into bitmaps before being printed or displayed. For example, PostScript printers have a raster image processor (RIP) that performs the translation within the printer. Vector-graphic formats can differ dramatically. InDesign supports import and export of most common vector graphics (see Table 47). TABLE 47 InDesign-supported vector-graphics formats File format Import Export Related page-item boss DCS Yes No kEPSItem EPS Yes Yes kEPSItem PDF Yes Yes kPlacedPDFItemBoss PICT Yes No kPICTItem SVG No Yes N/A. You can export various content or documents to SVG file format, but there is no page item for SVG format. WMF Yes No kWMFItem For more information on importing vector graphics, see “Graphics import” on page 238. For more information on exporting vector graphics, see “Export to graphics file format” on page 243. 218 Graphics Fundamentals Graphic page items Graphic page-item settings Content fitting Sometimes the size of the graphic page item is not the same as the size of the parent graphics frame, causing the graphic to be displayed incorrectly. Usually, end users can move, resize, or rotate the graphic page item or the graphics frame in the same way as any other page item. Taking advantage of the relationship between the graphic page item and the graphics frame, InDesign has several content-fitting options: z Fit content to frame — Resizes the graphic page item to the same size as the graphics frame. z Fit frame to content — Resizes the graphics frame to the same size as the graphic page item. z Center content in frame — Moves the graphic page item to the center of the graphics frame. No resizing is involved. z Fit content proportionally — Resizes the graphic page item to barely fit the frame (i.e., the graphic page-item edge touches the frame vertically or horizontally), while maintaining the aspect ratio of the graphic page item. z Fill frame proportionally — Resizes the graphic page item while maintaining its aspect ratio until all white space in the frame is filled. If there is a selection, we recommend you use IFrameContentSuite or IFrameContentFacade where possible to perform these operations, though individual commands for these operations do exist. NOTE: These transformations of graphic page items and frames change only the IGeometry or ITransform objects. These transformations do not alter the structure of the graphic page item and frame objects. Clipping paths A clipping path crops part of the image so only part image appears through the shape you create. The clipping path is stored separately from its graphics frame, so you can freely modify one without affecting the other. The clipping path does not change the image; the clipping path affects only how the image is drawn. Clipping paths can be created in the following ways: z Use existing paths or alpha channels. You can add paths and alpha channels in Photoshop files. z Let InDesign generate a clipping path with Detect Edges. z Draw a path in the shape you want, and paste the graphic into the path. When you set or generate a clipping path, the clipping path is attached to the image, resulting in an image that is drawn clipped by the path and cropped by the frame. IPathGeometry aggregated on the graphic page-item bosses stores the clipping path. For more information on how a path is defined, see “Path geometry” on page 214. Graphics Fundamentals 219 Graphics Fundamentals Graphic page items The IClipSettings interface is aggregated on kWorkspaceBoss, kDocWorkspaceBoss, and each graphic page-item boss, to define preferences or individual graphic page items’ clipping-path settings. For more details on IClipSettings, see the API reference documentation. Not all settings in IClipSettings are required to determine a clipping path. For example, if you choose the kClipEmbeddedPath type, you need to know only the embedded path index. Settings like threshold, tolerance, and inset are required only to detect edges. We highly recommend you use the IClippingPathSuite selection-suite interface. Text wrap You can wrap text around the frame of any page-item object. The text-wrap data model is discussed in detail in the “Text Fundamentals” chapter. The path the text wraps around is defined by a separate page item, kStandOffPageItemBoss, which is accessible through IStandOffData, aggregated both on the graphic-frame boss (kSplineItemBoss) and graphic page-item boss (See Figure 83). Whenever the text-wrap object changes, the path is copied to the IID_ITEXTWRAPPATH interface (same implementation as IPathGeometry) of the graphic page-item boss; this improves the performance of text composition and screen redrawing. What makes the graphic page item special in text wrapping is that you can specify the contour options when the text-wrap mode is set to Wrap Around Object Shape. In addition to setting the text-wrap contour to the stroke bounding box of the graphics frame that owns a graphic page item, you also can specify that text wrap around any of the following: z The rectangle formed by the graphic's height and width (the stroke bounding box of the graphic page item). z Paths generated by edge detection. You can adjust edge detection manually, using a clipping path (“Clipping paths” on page 219). z The image’s alpha channel. z The image’s embedded Photoshop path. z The image’s clipping path. As with the clipping path setting, contour options for text wraps are specified by IStandOffContourWrapSettings aggregated on kWorkspaceBoss, kDocWorkspaceBoss, and individual graphic page-item bosses. We highly recommend you use ITextWrapFacade to manipulate text wraps, including setting contour options. Display performance Display performance is used to set the balance between graphic display speed and quality. You can specify the quality of how raster images, vector graphics, and transparencies are drawn to the screen. A display performance group is a set of values for these categories. NOTE: 220 Graphics display performance options do not affect output resolution when exporting or printing images in an InDesign document. When printing to a PostScript device, packaging for GoLive, or exporting to EPS or PDF, the final image resolution depends on the output options you choose when you print or export the file. Graphics Fundamentals Graphic page items The following display performance groups are available: z Fast — The highest display speed but the lowest display quality. In the standard setting for this group, InDesign draws a raster image or vector graphic as a gray box. z Typical — The default option for graphic page items. In the standard setting for this group, InDesign draws a low-resolution proxy image appropriate for identifying and positioning a graphic. z High Quality — The highest quality but the lowest display speed. In the standard setting for this group, InDesign draws a raster image or vector graphic at high resolution (i.e., uses the file provided by the graphic page item’s link). NOTE: Standard settings of display performance groups can be modified through the Display Performance area of the Preferences dialog box or programmatically. See the “Graphics” chapter of Adobe InDesign CS4 Solutions. These display performance groups are session preferences, represented by IDrawOptions, aggregated on kWorkspaceBoss (see Figure 82). The interface stores an array of DrawOptionsSet (also defined in IDrawOptions.h), corresponding to the fast, typical, and high-quality groups, respectively. Each group itself, represented by a DrawOptionsSet, has a set identifier and defines the qualities for each category, including vector, raster, and transparency. (For details, see the API reference documentation.) The array of DrawOptionsSet defines a twodimensional map that indicates whether the graphic page item should be displayed as a gray box, proxy image, or a high-resolution graphic, given a display group (such as fast) and a category (such as raster). You can contain the current active group by calling IDrawOptions::GetActiveSetID, and can set groups through the Edit > Preferences > Display Performance menu. Display-performance settings are not document-level preferences; instead, they are set as view preferences. IDrawOptionsSetID, aggregated on kLayoutWidgetBoss (see Figure 82), allows each layout presentation to have different default settings, even if they are of the same document. IDrawOptionsSetID stores a DrawOptionsSet as default settings when importing graphic page items. These settings can be set through the View > Display Performance menu. Individual graphic page items can have their own display-performance overrides. IDrawOptionOverrides, aggregated on kDrawablePageItemBoss—which is inherited by all graphic page item bosses (see Figure 82)—stores a display-performance group (DrawOptionsSet) for each graphic page item. Display performance overrides can be set through the Object > Display Performance menu. The IDisplayPerformanceSuite selection-suite interface facilitates the manipulation of display-performance settings. NOTE: To let page item overrides take effect, the IDrawOptions::GetIgnoreOverrides preferences flag must be kFalse. You can set this flag through the View > Display Performance menu. The display-performance object model is summarized in the class diagram in Figure 82. Graphics Fundamentals 221 Graphics Fundamentals Graphic page items FIGURE 82 Display-performance object model The application preferences The layout view The individual graphic page item «boss» kWorkspaceBoss IDrawOptions «boss» kLayoutWidgetBoss 1 IDrawOptionsSetID «boss» kImageItem/... 1 IDrawOptionOverrides IDrawOptionsSetID::GetID 1 IDrawOptions::GetActiveSetID 1..* IDrawOptionOverrides::GetDrawOptions 1..* «struct» DrawOptionsSet 1..* Represents a display performance group, which stores settings for raster images, vector graphics, transparency, etc. Drawing a graphic page item Changing display performance from typical to fast does not replace a proxy image with a gray box directly. In fact, changing display performance does not change the instance of the graphic page item at all. The effect is achieved by invalidating the layout and letting the page-item drawing process take care of displaying. Drawing a layout containing graphic page items follows a generic drawing process detailed in “Dynamics of drawing” on page 278. A graphic page item is drawn in the following steps: 1. Set the crop rectangle. This involves calculating the graphic page item’s bounding box, cropped by the frame bounding box and view bounding box. 2. Clip the graphics with their clipping paths. 3. Determine drawing options and draw the graphics. You can participate in the graphic page-item drawing process by implementing the custom, drawing event-handler extension pattern, described in “Extension patterns” on page 289. 222 Graphics Fundamentals Graphic page items Graphic page-item data model This section illustrates the data model and common interfaces for graphic page items. Graphic page-item boss-class inheritances Although graphic page items are represented by various boss classes (kImageBoss and bosses for vector graphics in Table 47), they share similar interfaces and demonstrate similar properties. kImageItem (the boss representing raster images), kPlacedPDFItemBoss, kEPSItem, kPICTItem, and kWMFItem directly or indirectly inherit from kDrawablePageItemBoss, which aggregates interfaces necessary for page-item drawing. For the complete inheritance graph for the bosses, see the API reference documentation; search for kDrawablePageItemBoss. Graphic page-item class hierarchy Graphic page-item boss classes have the following characteristics: z Are wrapped in a spline item (kSplineItemBoss). z Have text wrap around their contour or frame (represented as kStandOffPageItemBoss). z Store low-resolution proxy images as kImageInDB. z Store a link object (ILinkObject) which keeps the UIDRef(s) of link boss(es). A link boss, like kImportLinkBoss, links the link object (page item) and external graphic files. z May embed link resources internally as kPMPersistDataBlobBoss. Figure 83 is a simplified view of the graphic page items in the class hierarchy of an InDesign document. ILinkObject provides access to the link object, which can be used to access the linked graphic resource. If the link is embedded, IStoreInternal provides access to kPMPersistDataBlobBoss, which stores the bitmap of the image. IImageDataAccess provides access to the proxy image, and the bitmap of the images also are stored as kPMPersistDataBlobBoss, which is accessible through IPersistUIDData on kImageInDB. Navigation from the document root to the kSplineItemBoss is wrapped into a package, which is discussed in the “Layout Fundamentals” chapter. Graphics Fundamentals 223 Graphics Fundamentals Graphic page items FIGURE 83 Graphic page-item class hierarchy This package includes all ancestors of a spline page item. See details in the "Layout Fundamentals" section about how to navigate to the page item. Document hierarchy Stores the path geometry of text wrap. 1 owns 0..* «boss» kSplineItemBoss The graphic frame wrapping the image page item. IPathGeometry «boss» kStandOffPageItemBoss 1 The graphic page items such as kImageItem, kPlacedPDFItemBoss, kEPSItem, kPICTItem, kWMFItem, or other graphic page item bosses. IHierarchy::QueryChild(0) 1 1 «boss» Any graphic page item boss IGeometry IPathGeometry IID_ITEXTWRAPPATH(IPathGeometry) 1 1 kImageInDB stores a lowresolution image (of a high-resolution image) IImageDataAccess:: GetLowResImageUID() IGraphicItem IImageItem(kImageItem only) IImageAttributes(kImageItem only) 1 ILinkObject::GetLinks IStoreInternal::GetStoredUID() 0..1 IImageAttributes 0..1 IStandOffData::GetStandOffUID() 0..* «boss» kImageInDB 1 0..1 IPersistUIDData::GetUID() «boss» kImportLinkBoss «boss» kPMPersistDataBlobBoss 0..1 Stores whole image internally as a blob. Could be either proxy image (from IPersistUIDData) or embedded image (from IStoreInternal). Stores the link of an external graphic file. Graphic page-item interfaces Several common interfaces are aggregated on graphic page-item bosses to provide features specific to graphic page items. These interfaces are either aggregated directly on the boss (e.g., kPlacedPDFItemBoss), or aggregated by way of their parent bosses (e.g., kImageBaseItem, the parent of kImageItem, or kDisplayListPageItemBoss, the parent of all other vector graphic page item bosses). Table 48 summarizes these important interfaces and their uses. 224 Graphics Fundamentals Graphic page items TABLE 48 Graphics-interface summary Interface ID Interface Description IID_IGRAPHICITEM IIntData This is the signature interface for all graphic types (raster, EPS, etc.). The integer data is never used. IID_IIMAGEITEM IImageItem Aggregated onto kImageBaseItem, this interface provides access to the embedded color profile of the image. More importantly, testing the presence of this interface verifies that a page item boss is a raster image. IID_IGEOMETRY IGeometry This interface defines the geometry (position, size, etc.) of a graphic page item. It is used for calculating cropping during the graphic page-item drawing process. IID_IPATHGEOMETRY IPathGeometry This interface stores the clipping path of a graphic page item (see “Clipping paths” on page 219). IID_ITEXTWRAPPATH IPathGeometry This interface stores the text-wrap path; however, this path is only a cache (or mirror) of the text-wrap path. The real path is stored at IPathGeometry on kStandOffPageItemBoss. Every time the real text-wrap path is changed, this path is updated. (See “Text wrap” on page 220.) IID_IIMAGEATTRIBUTES IImageAttributes This interface stores a set of tags to describe the attributes of a raster image. Predefined tags are defined as enumerators, each of which describes the type, length, and data of a raster image. These tags are crucial in defining image item properties, such as alpha channel, clipping path, and color profile. Proxy images When a graphic is placed, the contents of the original file are not actually copied into the document. Instead, InDesign creates a link to the original file on the disk and adds a screen-resolution bitmap image (the proxy image) to the layout, so you can view and move the graphic. When you export or print, InDesign uses the link to retrieve the original graphic, creating the final, desired, full-resolution output. Although end users can set preferences to tell InDesign to show high-resolution images (see “Display performance” on page 220), by default InDesign shows a low-resolution proxy image for performance reasons; the proxy image is created by processing kCreateLowResImageCmdBoss during the import process. A proxy image is represented by the boss kImageInDB, which is accessible from the graphic page item through IImageDataAccess::GetLowResImageUID. The connection is established during the image-import process. For the data model of the proxy image in relation to the graphic page items, see “Graphic page-item class hierarchy” on page 224 and “Graphic pageitem examples” on page 226. One of the most important interfaces on kImageInDB is IPersistUIDData, which holds a UID pointing to an instance of kPMPersistDataBlobBoss, which stores the bitmap of the proxy image. Graphics Fundamentals 225 Graphics Fundamentals Graphic page items The proxy image is not always created by asking the image-import filter for the data. For raster images, if image auto-embedding is allowed in the image-import preferences, and the image is smaller than a predefined amount (defaults to 48 KB, accessible through ILinkState::GetEmbedSize), the original high-resolution image is embedded directly. Creating a proxy image is aided by the IImageStreamManager interface, which provides a mechanism to convert the source-image format to a destination-image format according to the image attributes. Graphic page items and links Every graphic page item that was placed from a file has an associated link. End users can choose the Embed Link menu in the Links panel’s fly-out menu to embed the link manually. The file remains in the Links panel, marked with an embedded link icon. NOTE: This behavior differs from link for a text file. You can create a link when placing a text file; however, since text is inheritently part of the InDesign document, you cannot really “embed” the link. If you create a link when placing a text file, you can choose to unlink the file from the Links panel. Once it is unlinked, the link is removed from the Links panel. As a software developer, you also can use ILinkFacade::EmbedLinks to embed the image link (ILinkFacade is aggregated on kUtilsBoss). kStoreInternalCmdBoss, processed internally, reads the original high-resolution file and stores the image data as a data blob, referenced by the IStoreInternal interface on the graphic page item. Embedding a link is not the same as embedding the small image to create a proxy image, discussed in “Proxy images” on page 225: z The image data is stored in a different place. Embedding a link stores a data blob referenced by IStoreInternal on the graphic page item. Embedding an image as a proxy stores the data blob referenced by IPersistUIDData on kImageInDB boss. z Embedding a link does not cause a check for the size of the image.Embedding an image as a proxy requires the image file to be smaller than a predefined size. Graphic page-item examples New graphics can be placed into a layout with or without an existing graphics frame. This section illustrates how instances of graphics objects evolve as you place a PDF file, replace it with an image, move the image around, embed a link, and set clipping-path and text-wrap contour options. 226 Graphics Fundamentals Graphic page items Begin with an empty graphics frame We start exploring the graphics object model by examining an empty graphics frame. Figure 84 shows a screenshot and the object model when only an empty graphics frame is created. The graphics frame is represented by kSplineItemBoss, and it does not have any hierarchical children. FIGURE 84 Empty graphics frame Above: Empty links panel. Right: Empty graphic frame. Below: A graphic frame represented as kSplineItemBoss. No child object. Document hierarchy «boss» graphic-frame : kSplineItemBoss The graphic frame. Its pasteboard coordinates are shown. LeftTop = (36, -360) RightBottom = (276, 0) Graphics Fundamentals 227 Graphics Fundamentals Graphic page items Place a PDF item in a graphics frame Next, we place a PDF file into the graphics frame. During import, InDesign creates a kPlacedPDFItemBoss object to represent the PDF item and adds it as a child of the graphics frame. Figure 85 shows the object model of the graphics frame with a PDF item. A few other objects are created to represent information of the PDF item. New objects are marked in yellow. Comparing Figure 85 to Figure 84, notice the Links panel shows a link to the external PDF file. The link is represented by kImportLinkBoss through ILinkObject, aggregated on kPlacedPDFItemBoss. A proxy image is created for the PDF item as kImageInDB boss (UID 0xcd), and the proxy image bitmap is represented by kPMPersistDataBlobBoss (UID 0xce). By default, a graphic page item is put into the graphics frame with an offset of (0,0) in inner coordinate space, so the PDF item has the same PMRect::LeftTop position (obtained from IGeometry::GetPathBoundingBox) on the pasteboard as the graphics frame. Although the PDF item is slightly wider than the frame (PMRect::RightBottom member), InDesign does not draw that part, because it is cropped by the frame. 228 Graphics Fundamentals Graphic page items FIGURE 85 PDF item in graphics frame Area not cropped by frame Above: A PDF file appears in the Links panel. Right: PDF item placed in the graphic frame. Below: The graphic frame now has a PDF item represented by kPlacedPDFItemBoss. Document hierarchy The graphic frame is not changed. «boss» graphic-frame : kSplineItemBoss LeftTop = (36, -360) RightBottom = (276, 0) The PDF item is the only child of the graphic frame. It is wider than, but shorter than the graphic frame. A proxy image is created for the PDF file. «boss» PDF : kPlacedPDFItemBoss «boss» proxy image : kImageInDB UID = 0xcb LeftTop = (36, -360) RightBottom = (298, -200) UID = 0xcf UID = 0xcd «boss» image blob : kPMPersistDataBlobBoss «boss» link : kImportLinkBoss A proxy image is stored as a data blob. Link maintains a connection to external PDF file. UID = 0xce Graphics Fundamentals 229 Graphics Fundamentals Graphic page items Replace a PDF item with an image Next, we import an image file to replace the PDF item and examine the changes to the object model. Figure 86 shows the screenshot and object model after the change. Again, new objects are marked in yellow. Note the following: 230 z The Links panel shows a link to the new image file (PalmTreeCMYK.tif). z The overall structure of the object model did not change, but a new boss object kImageItem replaced kPlacedPDFItemBoss. z The UID of the link, proxy image, and proxy image data blob also changed. These objects were created during the import process—and the old objects were deleted. Graphics Fundamentals Graphic page items FIGURE 86 Imported image Above: New image appears in the Links panel. Right: Image replaced PDF item in the graphic frame. Below: The graphic frame now has an image represented by kImageItem. Document hierarchy The graphic frame is not changed. «boss» graphic-frame : kSplineItemBoss LeftTop = (36, -360) RightBottom = (276, 0) The image is the only child of the graphic frame. It is larger than the graphic frame, thus only a portion is shown. A proxy image is created for the the image file. «boss» image : kImageItem «boss» proxy image : kImageInDB UID = 0xb3 LeftTop = (36, -360) RightBottom = (418, 302) «boss» link : kImportLinkBoss UID = 0xb7 UID = 0xb4 «boss» image blob : kPMPersistDataBlobBoss A proxy image is stored as a data blob. Link maintains a connection to external image file. UID = 0xb5 Graphics Fundamentals 231 Graphics Fundamentals Graphic page items Move an image within a frame You may have noticed the palm tree image is large, and we can only see a small part of the tree. Now we move the image a little bit within the graphics frame, using the Direct Selection tool. Figure 87 shows the resulting object model. Everything is the same, except the pasteboard coordinates of the image item. The changed object is marked by a red circle; changed values are marked in yellow. The coordinates represent the bounding box of the image item. 232 Graphics Fundamentals Graphic page items FIGURE 87 Image moved within a frame Right: The image is moved to a new location within the graphic frame. The graphic frame is not changed. Document hierarchy A proxy image is created for the the image file. «boss» graphic-frame : kSplineItemBoss LeftTop = (36, -360) RightBottom = (276, 0) «boss» proxy image : kImageInDB UID = 0xb4 «boss» image blob : kPMPersistDataBlobBoss UID = 0xb5 «boss» image : kImageItem After the move, the image has new pasteboard coordinates. «boss» link : kImportLinkBoss UID = 0xb7 UID = 0xb3 LeftTop = (-84, -528) RightBottom = (298, 134) Link maintains a connection to external image file. A proxy image is stored as a data blob. Graphics Fundamentals 233 Graphics Fundamentals Graphic page items Embed an image’s datalink Next, we manually embed the image into the document by choosing Embed Link on the Links panel fly-out menu. Figure 88 shows the changed object model after the image is embedded. The new object is within the red circle, marked in yellow. A new kPMPersistDataBlobBoss is created to store the embedded image information. Other bosses—including the link object (kImportLinkBoss)—do not change. There are two kPMPersistDataBlobBoss objects in the object model, but they represent different things. The one accessible through IPersistUIDData on the proxy image:kImageInDB boss represents the proxy image; the other—accessible through IStoreInternal on the image:kImageItem boss—represents the embedded image data. 234 Graphics Fundamentals Graphic page items FIGURE 88 Embedded image The image is embedded into the InDesign file. The look and feel of the image does not change. Document hierarchy The graphic frame is not changed. A proxy image is created for the the image file. «boss» graphic-frame : kSplineItemBoss LeftTop = (36, -360) RightBottom = (276, 0) Embedding the image does not change pasteboard coordinates. «boss» proxy image : kImageInDB «boss» image : kImageItem UID = 0xb4 UID = 0xb3 LeftTop = (-84, -528) RightBottom = (298, 134) 1 IPersistUIDData::GetUID() 1 IStoreInternal::GetStoredUID() 1 1 «boss» image blob : kPMPersistDataBlobBoss «boss» embedded image blob : kPMPersistDataBlobBoss UID = 0xb5 UID = 0xd8 A proxy image is stored as a data blob. Graphics Fundamentals «boss» link : kImportLinkBoss UID = 0xb7 Link maintains a connection to external image file. Embedded image blob (orignal graphic file data), accessible through IStoreInternal. 235 Graphics Fundamentals Graphic page items Setting clipping path and text wrap Let’s use a different image to set clipping-path and text-wrap options. In this section, we place a linked image, overlap it on top of a text frame, and examine how the image and text frame change when you set clipping-path and text-wrap options. Figure 89 shows examples of clipping-path options. In the left screenshot, no clipping path was set, so the image overlaps the background text. The center screenshot shows the result of the clipping-path Detect Edges option (with the Threshold parameter set to 150). Although Detect Edges can detect most of the contours of the bottle, the result looks even better if you use the existing Photoshop paths, as shown in the right screenshot. FIGURE 89 Image clipping path set to None Clipping-path options Clipping path is generated by detecting edges. Clipping path set to existing Photoshop path. Reminder: The clipping path is stored with the IPathGeometry interface of the graphic page item, so no extra object is created. For the graphic page item’s class diagram, see Figure 83; for descriptions, see “Clipping paths” on page 219. Now we set the text wrap of the image item, shown in Figure 90. All three screenshots were taken with the text wrap set to wrap around the graphic page item’s object shape. The left screenshot shows the result when the text-wrap contour option is set to Same As Clipping, with clipping-path type set to Detect Edges. The top-right corner of the bottle frame does not have text, because a small part of the image is there. You can set the contour option to use existing Photoshop paths independent of the clipping path, shown in the center screenshot. You also can set both the clipping path and text-wrap contour options to use the Photoshop path, which produces the best result, as shown in the right screenshot. Object model changes after setting the text-wrap options are shown in the lower part of Figure 90. A new kStandOffPageItemBoss object—within the red circle, marked in yellow—is created to hold the text-wrap path. For information on how this affects text composition, see the “Text Fundamentals” chapter. 236 Graphics Fundamentals Graphic page items FIGURE 90 Text-wrap options Clipping path is set to detect edges, and text wrap is set to Same As Clipping The graphic frame Clipping path is generated by detecting edges. Text wrap is set to use Photoshop path Both clipping path and text wrap are set to use existing Photoshop path. «boss» graphic-frame : kSplineItemBoss LeftTop = (156, 123) RightBottom = (288, 336) The image item A proxy image is created for the the image file. «boss» proxy image : kImageInDB UID = 0xd2 «boss» image : kImageItem UID = 0xd1 LeftTop = (156, 123) RightBottom = (308,350) «boss» image blob : kPMPersistDataBlobBoss «boss» text wrap : kStandOffPageItemBoss UID = 0xd3 UID = 0xd7 A proxy image is stored as a data blob. Graphics Fundamentals «boss» link : kImportLinkBoss UID = 0xd4 Link maintains a connection to external image file. The standoff object, which stores the path geometry of the text wrap. 237 Graphics Fundamentals Graphic page items Graphics import Overview of the import process When a user chooses to place a graphic into a document, InDesign performs a sequence of steps to import the graphics file as a graphic page item. Figure 91 shows the steps involved in importing PDF, EPS, and image files. You also can import another InDesign document to a document. The import process works like PDF import. The only difference is importing InDesign document also imports swatches, inks, fonts and links, etc. and creates secondary links if the document being imported also contains links. You can set InDesign document-import options like other graphic file types; see “InDesign document-import preferences” on page 242. 238 Graphics Fundamentals Graphic page items FIGURE 91 Graphics-import process Create a link that connects the page item and link resource Choose import provider based on file type [Vectors (except PDF)] [PDF] [Raster Images] Choose image read format provider Create kPlacedPDFItemBoss New kImageItem Create EPS, DICT or WMF item Set PDF import prefs Set image IO prefs Set EPS import prefs Set PDF attributes Set Image attributes Set EPS attributes Generate raster preview Create kImageInDB Create TIFF proxy kImageInDB Stream into kImageInDB Embed image? [no] [yes] Sample high-resolution image Read and set proxy image's data blob Graphics Fundamentals 239 Graphics Fundamentals Graphic page items At a high level, the process involves the following steps: 1. Create a kImportLinkBoss that connects the link resource and the page item. 2. Query for an import provider that provides kImportProviderService for the graphic. This service also is used for importing other types of files, like plain-text files. For graphics files, one of four providers is called: kPDFPlaceProviderBoss, kImagePlaceProviderBoss, kEPSPlaceProviderBoss or kNativeImportServiceBoss. See Table 49 for details on file formats supported by these providers. 3. Create the appropriate new page item according to the type of the graphics file. See Table 49. 4. Import the file and set new page-item attributes, like IPDFAttributes, IEPSAttributes, and IImageAttributes. This may involve searching for an appropriate image import filter (“Image-import filters” on page 242) and setting import options (“Import options” on page 240). 5. Create and set a low-resolution proxy image for the new page item, which is accessible through IImageAccess on the new page item. TABLE 49 Supported graphic-file formats for import Import provider Filename extension Page-item boss kEPSPlaceProviderBoss AI, EPS, DCS kEPSItem kEPSPlaceProviderBoss PCT, PIC kPICTItem kEPSPlaceProviderBoss WMF, EMF kWMFItem kImagePlaceProviderBoss TIF, TIFF, SCT, PSD, PNG, PCX, JPEG, JPG, GIF, DIB kImageItem kPDFPlaceProviderBoss PDF kPlacedPDFItemBoss kNativeImportServiceBoss INDD kInDesignPageItemBoss Import options To control how the file should be imported, end users can choose Show Import Options in the Place dialog box, which allows the user to set import options through an Import Options dialog box. The specific options depend on the file type and graphics data in the file. PDF-import preferences The IPDFPlacePrefs (IID_IPDFPLACEPREFS) interface allows you to set various PDF import options, like how to crop the graphic and which pages to import. If the PDF file contains layers, you can set up layer information on the dialog using IGraphicLayerInfo. Both interfaces are aggregated on kWorkspaceBoss. IGraphicLayerInfo can be initialized by the imported file before bringing up the Import Options dialog. Table 50 lists some default settings of IPDFPlacePrefs. 240 Graphics Fundamentals Graphic page items For details, see the “PDF Import and Export” chapter. TABLE 50 Selected default PDF-import preferences Preference Default value Crop kCropToContent Page number 1 Proxy resolution 72 Show preview kTrue Transparent background kTrue EPS-import preferences IEPSPreferences (IID_IEPSPREFERENCES) also is aggregated on kWorkspaceBoss. Some settings are set programmatically; for example, importing an EPS graphic from a file (not from the clipboard) automatically sets the import mode to “import whole” (kImportWhole). Table 51 lists some default settings of IEPSPreferences. TABLE 51 Selected default EPS-import preferences Preference Default value Import mode kImportWhole Display resolution 72 Read OPI comments kDontReadOPIComments Create frame kDontCreateFrameFromClipPath Create proxy kCreateIfNeeded NOTE: “Create frame” corresponds to the Apply Photoshop Clipping Path checkbox, and kAlwaysCreate corresponds to the Rasterize The PostScript radio button in the EPS Import Options dialog box. Image-import preferences The Raster Image Import Options dialog box uses separate panels to set raster image-specific import options, like color profile and clipping path. Usually, InDesign uses session preferences (IImageIOPreferences on kWorkspaceBoss) to import an image file. Table 52 lists some of the default settings. Graphics Fundamentals 241 Graphics Fundamentals Graphic page items TABLE 52 Selected default image-import preferences Preference Default value Allow auto-embedding kTrue Create clip frame kTrue Preview resolution 72 When auto-embedding is allowed and the image size is small, InDesign automatically embeds the high-resolution image as the proxy image, so the data and the interfaces of kImageInDB reflect the high-resolution image rather than a new, low-resolution image. InDesign document-import preferences Placing InDesign document directly into an InDesign document has advantages in the publishing workflow, including automatically maintained links, fonts, swatches, links and so on. The IImportDocOptions (IID_IIMPORTDOCOPTIONS) interface allows you to set various InDesign document-import options, like how to crop the pages, which pages to import, and where to display previews. IGraphicLayerInfo let you set up layer information on the dialog to choose which layer to import. Both IImportDocOptions and IGraphicLayerInfo are session preferences aggregated on kWorkspaceBoss. They also store information to pass to kImportDocCmdBoss, if you want to use the command directly to place InDesign files. Table 53 lists some default settings of IImportDocOptions. TABLE 53 Selected default InDesign document-import preferences Preference Default value Crop kCropToPage Page number 1 Show preview kTrue Image-import filters You may have noticed in Table 49 that the same kImagePlaceProviderBoss is used for importing various kinds of raster images. These raster images have different file formats and, therefore, they need different ways to read data. InDesign provides another level of abstraction: the image-import provider queries for service providers that support kImageReadFormatService. This mechanism also serves as another extension pattern software developers may implement to support new raster-image formats. InDesign implements a set of providers to read various image formats, to import TIF (TIFF), SCT, PSD, PNG, PCX, JPEG (JPG), GIF, and DIB files. These providers serve as the imageimport filters. When InDesign is instructed to place an image, it iterates over all the providers until it finds one that can import the image. See Table 54 for a list of these providers. 242 Graphics Fundamentals Graphic page items TABLE 54 Image read-format providers File type Image read-format provider TIF kTIFFImageReadFormatBoss SCT kSCTImageReadFormatBoss PSD kPSImageReadFormatBoss PNG kPNGImageReadFormatBoss PCX kPCXImageReadFormatBoss JPEG kJPEGImageReadFormatBoss GIF kGIFImageReadFormatBoss DIB kDIBImageReadFormatBoss Export to graphics file format InDesign supports exporting all or part of a document to PDF, EPS, SVG, and JPEG formats. All the export processes are alike at a high level: exports are implemented using the IExportProvider service-provider mechanism (see the “Service Providers” chapter of Learning the Adobe InDesign CS4 Architecture). Each type of export destination format provides export services. Table 55 lists export providers that export to a graphics file format. TABLE 55 Graphic-export providers Export destination Export provider PDF kPDFExportBoss EPS kEPSExportBoss SVG kSVGExportProviderBoss JPEG kJPEGExportProviderBoss For examples of export provider implementations, see SDK samples like CHMLFilter, TextExportFilter, and XDocBookWorkflow. Each export provider has a corresponding command that exports content to a desired file format in the following two stages: 1. Drawing — Drawing page items to an intermediate entity, such as a viewport. 2. Streaming — Writing the content to the provided file stream. Export to PDF and EPS are discussed in detail in the “Exporting to EPS and PDF” section of the “Printing” chapter. PDF import and export also are discussed in the “PDF Import and Export” chapter. Graphics Fundamentals 243 Graphics Fundamentals Graphic page items Only SVG and JPEG export are discussed in this section. Figure 92 shows high-level activities of SVG and JPEG export. FIGURE 92 SVG and JPEG export process Get export file format Choose export provider [SVG] 244 [JPEG] Set SVG export prefs Set JPEG export prefs Create kSVGExportViewPortBoss and set attributes Create SnapshotUtilsEx Install draw event handler Draw page items on SnapshotUtilsEx Set up SVGWriter Create output stream Draw page items Export to JPEG stream Graphics Fundamentals Graphic page items SVG export SVG export preferences Settings for SVG export are stored with the ISVGExportPreferences interface on kWorkspaceBoss. For details, see the API reference documentation. End users can modify the preferences through the SVG Export Options dialog box. You also can change the preferences programmatically, with the kSVGExportSetPrefsCommandBoss command. Table 56 lists some of the default SVG-export preferences. TABLE 56 Selected default SVG-export preferences Preference Description Default value Embed fonts Whether to embed fonts in the SVG file kTrue Embed image Whether the image should be embedded in the SVG file kTrue Export bitmap sampling Sampling quality kHiResSampling Image format Image format kDefaultImageFormat, which is set to the same as kPNGImageFormat JPEG quality Image quality kJPEGQualityMed Page item export Whether to export the selected page item only kFalse Range format The range of pages to export kAllPages Exporting to SVG format InDesign exports to SVG format by drawing page items and documents to a special viewport, kSVGExportViewPortBoss. For more information about viewports, see “Data model for drawing” on page 276. kSVGExportCommandBoss aggregates ISVGExportController, which controls the drawing process and hides much of the complexity involved in SVG export. kSVGExportViewPortBoss aggregates ISVGWriterAccess, which helps in writing contents to an SVG file stream. JPEG export JPEG export preferences Settings for JPEG export are stored with the IJPEGExportPreferences interface on kWorkspaceBoss. For details, see the API reference documentation. End users can modify the preferences through the JPEG Export Options dialog box. You also can change the preferences programmatically, with the kJPEGExportSetPrefsCommandBoss command. Table 57 lists some of the default JPEG-export preferences. Graphics Fundamentals 245 Graphics Fundamentals Colors and swatches TABLE 57 Selected default JPEG-export preferences Preference Description Default value Export bitmap sampling Sampling quality kHiResSampling JPEG quality Image quality kJPEGQualityMed Range format The range of pages to export kAllPages Exporting to JPEG format kJPEGExportCommandBoss creates a SnapshotUtilsEx object and draws document contents on it. kJPEGExportCommandBoss then calls SnapshotUtilsEx::ExportImageToJPEG to write to the file stream. SnapshotUtilsEx also has methods to export to TIFF and GIF formats, so you can export to TIFF and GIF if you write your own export command, though you may need to provide your own image-write format boss. In the case of JPEG, the write-format boss provided is kJPEGImageWriteFormatBoss. For more information on SnapshotUtilsEx, see “Snapshots” on page 285. For use of SnapshotUtils (the older version of SnapshotUtilsEx, see the Snapshot SDK sample plug-in). NOTE: Multiple JPEG files are created for documents with multiple pages. Colors and swatches This section examines the data model for swatches, colors, and gradients. Architecture This section covers the representation of color, a fundamental graphic property, in the InDesign API. When we talk about color in the context of InDesign, we refer to the following: 246 z A color system refers to how colors and gradients are represented and printed and how to achieve consistent color throughout different applications and different devices. See “Color management” on page 252. z A rendering attribute of a page item refers to how a color or gradient can be used to render a page item’s graphic attributes, like stroke and fill. See “Graphic attributes” on page 256. Graphics Fundamentals Colors and swatches Figure 93 shows some key color-related concepts and how they appear in the user interface. FIGURE 93 Color concepts Color-related panels Linear gradient Graphics Fundamentals Radial gradient Color Tint Color applied Swatches 247 Graphics Fundamentals Colors and swatches Figure 94 shows some of the key color-related concepts and the relationships among them. FIGURE 94 Conceptual model for color A swatch is a rendering object that can render document objects. It can be normal color, tint, mixed ink, or gradient. Color could be of type process or spot. Gradients are continuous, smooth color transitions along a vector from one color to another. It could be linear or radial type. swatch «subtype» «subtype» «subtype» 1 gradient «subtype» 1..* based on 1 «subtype» -Composite «subtype» color 1 radial «subtype» linear tint spot Tint is a percentage of a color. process A mixed ink consists of at least one process color ink and at least one spot color. based on 1..* 11 based on 1..* mixed ink Figure 95 is a UML class diagram involving color-related boss classes. It shows the relationship among color and swatch–related boss classes. The relationships also apply if you replace kDocWorkspaceBoss with kWorkspaceBoss. 248 Graphics Fundamentals Colors and swatches FIGURE 95 Color-related boss-class diagram IID_ISWATCHLIST and IID_IUICOLORLIST share the same interface ISwatchList, but have different implementations (kSwatchListImpl and kUIColorListImpl respectively). kPMColorBoss from IID_ISWATCHLIST is a swatch, kPMColorBoss from IID_IUICOLORLIST is a UI color. The document workspace «boss» kDocWorkspaceBoss 1 1 11 1 IID_ISWATCHLIST «boss» kGraphicStateNoneRenderingObjectBoss 0..* 1 IID_IINKLIST IID_IUICOLORLIST, IID_ISWATCHLIST «boss» kAGMBlackBoxRenderingObjectBoss 0..* 1 «boss» kGradientRenderingObjectBoss 0..* 0..* * «boss» kPMColorBoss 1 1 IGradientFill::GetNthGradientColorUID() 1 * * «boss» kPMInkDataBoss * IInkResources::GetUsedInks(). ** These four bosses represent swatches. Comparing Figure 95 to the to the conceptual diagrams, note the following: z The kDocWorkspaceBoss is used here to show where these boss classes belong. These interfaces also exist on kWorkspaceBoss. z The boss objects of type kPMColorBoss and kGradientRenderingObjectBoss and other classes represent swatches directly. IRenderingObject is the signature interface. z kPMColorBoss implements solid color, tint, mixed ink, process color, and spot color. When swatches are created, modified, or deleted, the state of the swatch list changes. For a detailed discussion of these changes, see “Swatch-list state” on page 296. Graphics Fundamentals 249 Graphics Fundamentals Colors and swatches Swatches A swatch is an abstraction that can represent a color, gradient, tint or mixed ink. A rendering object implements the IRenderingObject interface. IRenderingObject represents information about a color or gradient and exposes capabilities to render this information to a device. The following are some of the boss classes that expose the IRenderingObject interface: z kPMColorBoss represents colors (including tint and mixed ink) z kGradientRenderingObjectBoss represents gradient. z kGraphicStateNoneRenderingObjectBoss represents the absence of rendering information; for example, this boss can represent no-fill or no-stroke attributes. This boss is used internally. z kAGMBlackBoxRenderingObjectBoss is used for special page items created from Adobe Illustrator® clipboard format. It is only for internal use. Some methods of IRenderingObject take an IGraphicsPort item as an argument. IGraphicsPort is an interface with methods that parallel PostScript operators like setcolorspace. The key responsibility of the rendering object implementation is to set up the color space, tint, and color components to draw to the graphics port. IRenderingObjectApplyAction is another required interface on rendering objects. For more details on IRenderingObject, IRenderingObjectApplyAction, IGraphicsPort, and the other interfaces on rendering object boss classes, see the API reference documentation. Solid colors Color is represented by the kPMColorBoss class, responsible for representing solid colors, including tints and mixed inks. In addition to the signature interface for a rendering object, IRenderingObject, kPMColorBoss aggregates several other interfaces, including the following: z IColorOverrides — Stores tint and color remarks so the kPMColorBoss also can represent tint and special color types (e.g., reserved color). For details, see the API reference documentation. z IInkData — Stores the ink information used by the color. InkType represents color type (process or spot). z IColorData — Represents color coordinates in a ColorArray vector and a color space. There are three color spaces of interest: z CMYK defines a color with four components: cyan, magenta, yellow, and black. Typically, these components are represented by percentages. z RGB represents colors with three components: red, green, and blue. Typically, these components are represented by values between 0 and 255. z LAB (more precisely, L*a*b*) is a device-independent color space See “Color management” on page 252. 250 Graphics Fundamentals Colors and swatches Gradients Gradients are represented by the kGradientRenderingObjectBoss boss class, which aggregates IRenderingObject as well as IGradientFill, representing gradient-specific properties. For details, see the API reference documentation. Gradients can be linear or radial; see the enum declaration of GradientType in GraphicTypes.h. A gradient consists of one or more ranges of color, which are smooth interpolations between gradient stop positions. The color is defined only at the gradient stop positions, with calculated color values at intermediate positions. For more detail on working with gradients, see “Gradients” in InDesign Help. Swatch lists Rendering objects (IRenderingObject) are referenced in a swatch list (ISwatchList). The swatch list (ISwatchList) is exposed on workspaces (IWorkspace). For examples of the swatch list (and ink list) when an end user creates and applies swatches to page items in a document, see “Swatch-list state” on page 296. If you create a color through the Color panel, or create a new gradient through the Gradient panel and then apply the gradient to a page item without creating a swatch beforehand, an unnamed (or local) swatch is created in the swatch list. The unnamed swatches do not appear in the Swatches panel, but they can be used for the strokes and fills of document objects by client code. User-interface color list Colors and color names that appear in the application user interface in places like the Layers panel and Tags panel are not the same ones used in representing color in the document. Userinterface colors also are stored in an ISwatchList interface on workspaces (IWorkspace), but with the interface identifier IID_IUICOLORLIST. User-interface colors are normally RGB only. A key utility interface for working with userinterface colors is IUIColorUtils. User-interface colors are represented by kUIColorDataBoss rather than a rendering-object boss class. Inks Colors are ultimately printed by means of inks; for example, CMYK color separation is performed before printing to a four-color press. Inks are represented by the kPMInkDataBoss boss class. The rendering object classes like kPMColorBoss or kGradientRenderingObjectBoss aggregate the IInkResources interface, with which you can refer to the inks used in a color (or other page item) by using the IInkResources::GetUsedInks method, then querying for IPMInkDataBoss. IInkData::GetInkUIDList returns an empty list when the color type is process. IInkData is an interface on kPMColorBoss. Graphics Fundamentals 251 Graphics Fundamentals Color management There is an IInkList interface on the workspace boss classes that specifies the inks needed for all swatches in the document and application. The ink list contains process inks and zero or more spot inks. The relation between inks and the swatch list is fairly direct: adding a new spot color to the swatch list and applying it to a document object results in a new entry in the ink list. However, creating another swatch that is a process color and applying it does not necessarily change the entries in the ink list, if the process inks needed to print this new color already are in the ink list. The ink-manager feature (Ink Manager in the Swatches panel menu) shows the inks associated with the contents of the swatch list. For example, if the swatches in the document were defined in terms of four process colors and two spot colors, the ink-manager user interface is similar to that shown in Figure 96. For information on how to work with the ink manager and iterate through the ink list, see the “Graphics” chapter of Adobe InDesign CS4 Solutions. FIGURE 96 Ink Manager dialog box It is necessary to preflight documents to ensure they print correctly when submitted to the press. As far as color is concerned, it is necessary to identify the inks that must be loaded in the press for a job to print correctly. Color management The purpose of color management is to get accurate color on all kinds of devices. Color-management modules provide color-conversion calculations from one device’s color space to another, based on ICC device profiles. For detailed descriptions of the color spaces used by InDesign, see “Color spaces” on page 300. 252 Graphics Fundamentals Color management ICC profiles An ICC profile is a record of the unique color characteristics of a color input or output device. An ICC profile contains data for the translation of device-dependent color to L*a*b* color. The following illustrates the concept of translation from the L*a*b* color space to RGB and CMYK color spaces using ICC profiles: z L*a*b* = RGB + ICC profile z L*a*b* = CMYK + ICC profile With an ICC profile, color-management systems can do the following: z Translate a user-defined, device-specific color to a device-independent, L*a*b* color. For example, if the user creates an RGB color for a specific computer monitor, that color could be translated to L*a*b*. z Translate a L*a*b* color to a device-specific color. For example, when printing to a printer, the L*a*b* color is translated to a CMYK color. Color-management workflow Color management within InDesign is relatively complex because of the following: z InDesign supports multiple color spaces per document. For example, a user could assign text in one paragraph an RGB color, another paragraph a CMYK color, and so on. z InDesign supports external links (by means of ILink) to assets that can have different color settings than those used in the document. There are three levels of ICC profile sets involved in InDesign: z Image ICC profile — This is embedded in the image file when the image is created. z Document ICC profile — This is associated with a particular InDesign document. z Application ICC profile preference — This is the default profile of the application. The default profile is assigned to any new document. InDesign features relating to color management are described comprehensively in “Color Management” in InDesign Help. Data model for color management The implementation of color management is somewhat complex. The class diagram in Figure 97 illustrates some color management-related boss class relationships in InDesign. Graphics Fundamentals 253 Graphics Fundamentals Color management FIGURE 97 Color management Application preferences The document workspace <<boss>> kWorkspaceBoss <<boss>> kDocWorkspaceBoss 1 1 The color profile. Note: although both application-preference and document-side bosses (kDocumentPresentationBoss and kImageBaseItem) can refer to a profile by UIDRef, they are pointing to different objects, because they are at different databases. 1 ICMSProfileList IColorPresetManager 0..* IColorPresetSettings <<boss>> kCMSProfileBoss 1..* 1 ICMSProofing <<boss>> kDocumentPresentationBoss 1..* 1..* ICMSProfileUID Color preset files Color preset files are installed during InDesign installation and shared with other Adobe applications. 1 <<boss>> kImageBaseBoss Document window for proofing Images may each have their own color profile. Color presets Outside the application, predefined Adobe color-management settings are stored in color preset files, which are saved at the following location: Windows: Program Files\Common Files\Adobe\Color\Settings\ Mac OS: Library/Application Support/Adobe/Color/Settings These presets are shared among all Adobe Creative Suite® applications, to make it easier to achieve consistent color across the suite. The kWorkspaceBoss boss class aggregates the IColorPresetsManager interface, which is responsible for managing the presets, like loading color pre- 254 Graphics Fundamentals Color management set files and saving customized presets. The settings of the current preset are populated into the IColorPresetsSettings interface on kWorkspaceBoss. The IColorPresetsSettings interface stores the working color-management settings of the application, like RGB and CMYK, the ICC profile, and color-management policies. In the user interface, the color-management settings are accessed through the Color Settings dialog box. Color profile The kCMSProfileBoss boss class represents a color profile. The ICMSProfile interface on kCMSProfileBoss stores information about the type and category of the profile. This interface has a method for getting and setting profile data by accessing the IACESpecificProfileData interface on the same boss. The ICMSProfileList interface, exposed on workspaces (IWorkspace), indicates which profiles are used, as either document profiles or image profiles, and which are assigned to specific document categories (e.g., document CMYK and document RGB). A profile can be assigned to each category of a document through Edit > Assign Profiles. Image settings Any imported image can have either an embedded profile or a profile already assigned to it. (See Object > Image Color Settings.) The ICMSItemProfileSource interface aggregated on the kImageBaseItem boss class stores the basic profile-assignment type (see the enumeration ICMSItemProfileSource::ProfileSourceType) and the name of the image's embedded profile, if any. If an image uses an external profile or an embedded profile, an interface IPersistUIDData (with interface identifier IID_ICMSPROFILEUID) stores the UID of an instance of kCMSProfileBoss, so you will be able to instantiate an interface on kCMSProfileBoss from this UID and get the profile data needed. There is no link from a specific profile to the images that use that profile. To find the images that use a specific profile in the profile list, you need to iterate through all images using the links manager (ILinksManager). Rendering intent The ICMSSettings interface is aggregated on docworkspace (kDocWorkspaceBoss) and the kImageBaseItem boss class, a superclass for image boss classes, which stores rendering-intent information for document and image page item. Please use the ICMSUtils interface to set rendering intent, rather than manipulating the ICMSSettings interface directly. For application defaults, rendering intent are determined by IColorPresetsSettings interface aggregated on kWorkspaceBoss. You can use GetIntent and SetIntent methods to manipulate rendering intent. Proofing The ICMSProofing interface is aggregated on kWorkspaceBoss, kDocumentPresentationBoss, and several user-interface panels. The implementation on kWorkspaceBoss is a proofing preference, and the implementation on kDocumentPresentationBoss is responsible for setting up drawing when users choose to proof their design using the Proof Setup dialog box. This ICMSProofing interface stores the proofing settings as well as a proofing profile. Graphics Fundamentals 255 Graphics Fundamentals Graphic attributes Graphic attributes A graphic attribute describes an aspect of how a page item should be drawn. There are many kinds of graphic attribute for properties like stroke color, fill color, stroke type, and stroke weight. This section introduces the concepts involved and describes specific sets of graphic attributes for features like page-item rendering. Graphic-attribute data model Figure 98 is a conceptual model of the graphic attributes associated with a page item. FIGURE 98 Graphic-attribute conceptual model A page item that carries a various number of graphic attributes Page item 1 owns A graphic attribute controls one aspect of the drawing of an object. 0..* Graphic attributes «subtype» «subtype» «subtype» «subtype» Stroke color Stroke color controls the color of stroke. Stroke style Stroke style attribute controls the style of stroke (dotted line, etc.). ... Other various attributes Gradient fill Gradient fill controlls fill of the object. Transparency Transparency controls the transparecy effect. A page item owns a collection of graphic attributes, specifying properties that control how the page item is drawn, like stroke color, stroke style, and transparency. Each attribute is responsi- 256 Graphics Fundamentals Graphic attributes ble for a single aspect of how the page item is drawn. A list of graphic attributes is represented by IGraphicStyleAttributeBossList. Figure 99 shows the graphic-attribute UML class model of a drawable page item. FIGURE 99 Graphic attributes on a page item IID_IGRAPHICSTYLE_IS_APPLICABLE can answer whether an attribute is applicable to the page item. Drawable page items such as Spline, Group, and Image have graphic attributes applied. 1 1 IID_IGRAPHICSTYLE_REFERENCE IGraphicStyleReference «boss» kDrawablePageItemBoss 1 1 IID_IGRAPHICSTYLE_IS_APPLICABLE IGraphicStateIsApplicable 1 «boss» kGraphicStyleBoss IID_IGRAPHICSTYLE_OVERRIDES IGraphicStyleAttributeBossList IID_IGRAPHICSTYLE_DESCRIPTOR IGraphicStyleDescriptor 1 1 IID_IGRAPHICSTYLE_DEFINITION IGraphicStyleAttributeBossList «partial-implementation» IGraphicStyleAttributeBossList 1 1 1 IGraphicStyleAttributeBossList is a list of individual graphic attribute boss objects. Iterating method 1 0..* Every individual attribute class inherits from kGraphicsAttrBoss. «boss» Individual kGraphicsAttrBoss IID_IGRAPHICSTYLE_DESCRIPTOR can be used to query an attribute or return a list of attributes applied to the page item. There are several important interfaces on a page item responsible for managing graphic attributes: z IGraphicStateIsApplicable. z IGraphicStyleAttributeBossList (IID_IGRAPHICSTYLE_OVERRIDES), which stores a list of graphic attributes that override those stored in a graphic style. Graphics Fundamentals 257 Graphics Fundamentals Graphic attributes z IGraphicStyleAttributeBossList. z IGraphicStyleDescriptor. z IGraphicStyleReference. For details on each interface’s responsibilities, see the API reference documentation. Representation of graphic attributes Graphic attributes are represented by boss classes with the signature interface IGraphicAttributeInfo. The graphic attributes in the application appear in the API reference documentation for IGraphicAttributeInfo. Typically, they derive from the kGraphicsAttrBoss boss class. The IGraphicAttributeInfo interface stores the name and type of the attribute. Some graphic attributes have corresponding text and table attributes. See “Mapping graphic attributes between domains” on page 260. Graphic attributes have additional data interfaces that specify their values. Because there are many graphic attributes, sometimes it is a challenge to determine which attribute boss corresponds to which attribute. For a description of attributes, see “Catalog of graphic attributes” on page 301. Most of the attributes represent a single value, like a boolean, int16, int32, PMPoint, or PMReal. These simple attributes generally are backed by interfaces like IGraphicAttrBoolean, IGraphicAttrInt16, IGraphicAttrInt32, IGraphicAttrPoint, and IGraphicAttrRealNumber. For example, kGraphicStyleEvenOddAttrBoss (IGraphicAttrBoolean) corresponds to the even-odd fill rule when you have a compound path; set it to kTrue to use the even-odd rule or to kFalse to use the default InDesign fill rule (non-zero winding fill rule). Some other attributes have UID values. For example, attributes related to object rendering refer to a rendering object through the IPersistUIDData interface. For more information, see “Rendering attributes” on page 261. Some other attributes have ClassID values, which are all stored with IGraphicAttrClassID. These attributes are used to specify stroke effects of a page item. See “Stroke effects” on page 262. Graphic styles A graphic style (kGraphicStyleBoss, UID-based) is a collection of graphic attributes. The IGraphicStyleNameTable interface exposed on workspaces (IWorkspace) stores the names and UIDs of graphic styles. There are two key interfaces on kGraphicStyleBoss: z IGraphicStyleInfo stores the name and UID for the style on which this style is based (the style from which this style inherits). z IGraphicStyleAttributeBossList (IID_IGRAPHICSTYLE_DEFINITION) stores the list of graphic attributes this graphic style owns. Only [No Style] is used in the InDesign CS4 and InCopy CS4 implementations. kGraphicStyleNoneBoss implements the default [No Style], which is set up during application start-up (for 258 Graphics Fundamentals Graphic attributes the session workspace) and document creation (for document workspace). This style stores default settings of various graphic attributes, like stroke weight as 1.0 and stroke type as solid line. Although there still is a public API to work with user-named graphic styles, these are deprecated since the introduction of object styles. Adobe applications do not define user-named styles using graphic styles as the container. We recommend you avoid using graphic styles for this purpose in your plug-ins. User-named styles are supported by the object styles feature. An object style is a style that defines the appearance of a page-item object. An object style contains settings of a set of attributes, including graphic attributes and text attributes. An object style is a superset of graphic style. Graphic state Graphic state is the representation of the current state of things related to the graphic attributes. Usually this is a collection of graphic attributes for the current selection or, if there is no selection, the current defaults. The graphic state is represented by kGraphicStateBoss. An active graphic state refers to the graphic state at the current context. Active graphic state can be accessed through IGraphicStateAccessor, aggregated on kDocWorkspaceBoss or kWorkspaceBoss. A reference to an interface of the active graphic state also can be acquired through IGraphicStateUtils::QueryActiveGraphicState, aggregated on kUtilsBoss. The kGraphicStateBoss boss class aggregates interfaces like IGraphicStateRenderObjects and IGraphicStateData. IGraphicStateRenderObjects This interface is key to the graphic state. It can be acquired from the IGraphicStateUtils utility interface by querying active graphic state or the graphic state of a specific database. For sample code that shows how to acquire the interface, see the “Graphics” chapter of Adobe InDesign CS4 Solutions. Given this interface, you can query the current IRenderingObject interface for the specified rendering class or the active rendering class in the graphic state. The active rendering could be fill or stroke. Changing the graphic state Changing any graphic attributes changes the graphic state. Virtually every user-interface action—like selecting a new swatch, picking a color in the Color Picker panel, switching fill and stroke, selecting a different stroke style, changing selection, or changing the front document— causes a change to current active graphic state. You can use methods on IGraphicAttributeUtils or IGraphicStateUtils to acquire appropriate commands. kGraphicStateBoss also aggregates an ISubject interface. Changes to the graphic state can be observed by listening along the IID_IGRAPHICSTATE_RENDEROBJECTS and IID_IGRAPHICSTATE_DATA protocols. Graphics Fundamentals 259 Graphics Fundamentals Graphic attributes Creating new page items using default attributes When a new page item is created, default attributes in the graphic-state boss objects are copied and applied to new page items when you specify INewPageitemCmdData::kDefaultGraphicAttributes as attrType parameter on spline creation methods on IPathUtils. Mapping graphic attributes between domains Some graphic attributes also can be applied to text or tables. For example, Figure 100 shows stroke and fill colors and gradients applied to text, table cells, and a spline item. Although the intent is the same in each case, the attributes differ in each case. Text and tables have some attributes corresponding to the graphic attributes. FIGURE 100 Stroke and fill attributes kGraphicStyleStroke RenderingAttrBoss (blue) kTextAttrStrokeColorBoss (yellow) kCellStrokeAttrDataBoss (red) kGraphicStyleFill RenderingAttrBoss (Gradient) kTextAttrColorBoss (Cyan) kCellAttrFillColorBoss (green) There are independent attributes for each of these domains. For example, an attribute represented by kGraphicStyleFillRenderingAttrBoss on a spline page item is represented by the kCellAttrFillColorBoss type when the attribute is applied to a table cell, and it is represented by the kTextAttrColorBoss type when the attribute is applied to a text run. When a graphic attribute is applied to a text run, there is a conversion process in which a new text attribute is applied as an override to the run. The same applies when trying to apply a graphic attribute to a table; the graphic attribute can be converted to a corresponding table attribute. Not all graphic attributes apply to text or tables. The IGraphicAttributeInfo::IsTextAttribute and IGraphicAttributeInfo::IsTableAttribute methods return kTrue if the corresponding attribute in the respective domain exists. IGraphicAttributeInfo::CreateTextAttribute returns a 260 Graphics Fundamentals Rendering attributes text attribute that maps onto the equivalent graphic attribute. Similarly, IGraphicAttributeInfo::CreateTableAttribute returns a table attribute that maps onto the equivalent graphic attribute. Each of these methods is expected to return a non-zero value if the Is<XXX>Attribute method returns kTrue. The selection suites (e.g., IGraphicAttributeSuite and IGradientAttributeSuite) make it straightforward for client code to change the properties of a selection; the client code needs to work with only the graphic attributes. There is no need to worry about whether the selection is text, choosing the specific text attribute, and whether the selection is text, table, or layout. The mapping between different domains is hard-coded. New graphic attributes added by thirdparty software developers may provide their own mapping by overriding the default implementations of IGraphicAttributeInfo. The mappings between graphic attributes and text attributes are shown in Table 85. The mappings between graphic attributes and table attributes are shown in Table 86. Note that the mapping between graphic attributes and table attributes is many-to-one rather than one-to-one because; for example, the kCellStrokeAttrDataBoss boss class can represent information about multiple stroke parameters, whereas each of the corresponding graphic attributes refers to one parameter. Rendering attributes A rendering attribute refers to a swatch to be used when drawing an aspect of a page item. Rendering attributes are a special kind of graphic attribute that refer to their associated swatch by UID. The swatch can be a color, gradient, tint, etc. Color-rendering attributes A page item’s stroke, fill, or gap can be rendered independently. Table 58 lists color-rendering attributes. TABLE 58 Color-rendering attributes Rendering-attribute class Description kGraphicStyleFillRenderingAttrBoss Fill rendering object kGraphicStyleFillTintAttrBoss Fill tint kGraphicStyleGapRenderingAttrBoss Gap rendering object kGraphicStyleGapTintAttrBoss Gap tint kGraphicStyleStrokeRenderingAttrBoss Stroke rendering object kGraphicStyleStrokeTintAttrBoss Stroke tint Graphics Fundamentals 261 Graphics Fundamentals Stroke effects Gradient attributes Page items also can be rendered using gradients; however, multiple graphic attributes are needed to represent a gradient. For example, you need to specify gradient fill angle, center, and length. There is no characteristic signature for a gradient attribute other than the boss class name; for the canonical graphic attributes, the boss-class name is of the following form: kGraphicStyleGradient<graphic_attribute>AttrBoss. A list of these boss classes is in the master attributes list in “Catalog of graphic attributes” on page 301. You can use the same color-rendering attributes class name to apply gradient attributes to page items. IRenderingObjectApplyAction::PreGraphicApply automatically forwards the attributes to appropriate gradient attributes. For example, if you are supplying kGraphicStyleFillRenderingAttrBoss, the method adds attributes including the following: z kGraphicStyleGradientFillAngleAttrBoss z kGraphicStyleGradientFillGradCenterAttrBoss z kGraphicStyleGradientFillHiliteAngleAttrBoss z kGraphicStyleGradientFillHiliteLengthAttrBoss z kGraphicStyleGradientFillLengthAttrBoss z kGraphicStyleGradientFillRadiusAttrBoss The situation gets more complicated by the possibility of applying gradients to table cells; when a gradient is applied to a table cell, additional cell-specific attributes are involved. For example, kCellAttrGradientFillBoss and kCellAttrGradientStrokeBoss are table-cell attributes representing properties of gradients. Stroke effects There are several graphic attributes that define the look and feel of the stroke of a page item. Some of these attributes are straightforward, like kGraphicStyleStrokeWeightAttrBoss, which defines stroke weight. Path stroker A path stroker is responsible for the basic drawing of a path. To find existing path-stroker boss classes, see the API reference documentation for IPathStroker. For information on how to add custom path strokers, see “Custom path-stroker effects” on page 289. IPathStrokerList allows you to access the list of available path strokers. IPathStrokerUtils provides utility methods to do the same thing. The kGraphicStyleStrokeLineImplAttrBoss boss class specifies the class ID of a path stroker that applies to a particular path. 262 Graphics Fundamentals Transparency effects Path corners A path-corner effect draws the corners of a stroked path. For a list of path-corner-effect boss classes, see the API reference documentation for IPathCorner. For information on how to add custom path corners, see “Custom corner effects” on page 290. The kGraphicStyleCornerImplAttrBoss boss class specifies the class ID of the corner effect. Path-end strokers A path-end stroker (IPathEndStroker) draws the start and end of a stroked path. To find pathend strokers, see the API reference documentation for IPathEndStroker. For information on how to add custom path ends, see “Custom path-end effects” on page 290. The kGraphicStyleLineEndStartAttrBoss boss class specifies the class ID of the line-end (for example, arrow) style at the starting side of a line. The kGraphicStyleLineEndEndAttrBoss boss class specifies the class ID of the line-end style at the terminating side of a line. Transparency effects Concepts Transparency effects are a set of graphic attributes that define color blending for overlapped page items and backgrounds. Common transparency effects include basic transparency, drop shadow, and feather. Figure 101 shows examples of transparency effects supported in InDesign. Graphics Fundamentals 263 Graphics Fundamentals Transparency effects FIGURE 101 No effect Drop shadow Inner shadow Outer glow Inner glow Bevel & emboss Satin Basic feather Directional feather Gradient feather 264 Transparency effects supported in InDesign Graphics Fundamentals Transparency effects These transparency effects can be divided into two classes: z Outer effects include drop shadow, outer glow, and outer bevel, and emboss. In this class of effects, a copy of the artwork is converted to raster; the raster has the effects applied and is then drawn first, the artwork is then drawn on top of the effect. (The exception is emboss, in which artwork is dean first then the effect is drawn on top) z Inner (clipped) effects include inner shadow, inner glow, inner bevel, satin, and feathers. The artwork fill and shape is combined with the effect parameters, and the result is a new fill for the artwork. Because the fill is clipped to the artwork shape, this class of effect is highly dependent on the type of artwork involved. Common controlling parameters Different transparency effects are controlled by different sets of parameters, Some of these parameters are used commonly in defining different transparency effects. Opacity Opacity is the converse of transparency. It represented by the following formula: opacity = (1.0 - transparency) Opacity is expressed as a percentage, where 0% is completely clear and 100% is completely opaque. Page items can have individual opacities assigned to them. Items can be grouped and have a group opacity assigned, which is combined with the individual opacities to calculate the resultant color on the backdrop. Blending mode Blending mode defines how the background (backdrop) and foreground (source) colors interact. In the physical world, transparency is the result of light passing through translucent materials. Blending modes are somewhat different: they do not try to model the complex physics of transparency; rather, they are analytic expressions that produce interesting visual effects. The following blending modes are encountered often: normal, multiply, and screen. There also are blending modes related to color spaces, like hue, saturation, and color-blending modes. Blending modes are vector functions that take as input the object source color and backdrop color and produce a resulting color that is the new color of the backdrop. This is not pixelbased blending; rather, this is in terms of points with no dimension. The colors that are the input for a blending function need to be specified in a common blending-color space (document CMYK or RGB). This is specified document-wide through the Edit menu. A blending mode is described by an analytic expression that specifies how to calculate the resultant backdrop color given the mode, current backdrop color, foreground color, and opacities of the background and foreground. Ordinarily, a blending function is a vector function: C_r = F(Mode, C_b, C_f, O_b, O_f) where C_r is the resultant backdrop color, Mode is the blending mode, C_b is the current backdrop color, O_b is the opacity of the backdrop, and O_f is the opacity of the foreground (source object). Graphics Fundamentals 265 Graphics Fundamentals Transparency effects In general, the blending function gives the resulting color at a point. The two-dimensional coordinates in the backdrop plane also can be specified in the expression above, to give an exhaustive expression for a blending function. Normal blending mode is a trivial blending mode, which specifies that the resulting blend is the value of the source color. The result of a normal blend is given by the following formula: B(C_b, C_s) = C_s where B is the blending function, C_b is the backdrop color, and C_s the source-object color. Multiply-blending mode is the scalar product of the backdrop color and the source object color. For an additive color space like RGB, the multiply-blending mode is calculated by taking the component-wise product of the two vectors. The multiply blending mode is given by the following formula: B(C_b,C_s) = C_b•C_s With an additive color space, the resulting blend color is darker than either of the two inputs, so the multiply-blending mode also is referred to as shadow mode. For a subtractive color space like CMYK, it is necessary to take the reciprocal of the colors. The expression for the blending mode is identical to the above, but with the substitution of (1-c) for the color. Screen-blending mode often is referred to as highlight mode. The analytic expression for screen blending mode is given by the following formula: B(C_b, C_s) = 1 - (1-C_s)•(1-C_b) This can be thought of as the reciprocal of multiply mode, in the sense that it is multiplying the reciprocal input colors and using the reciprocal of the result. The resulting components are larger than the corresponding input components, so the net effect is a highlight of the two colors. Position Position determines the location of a transparency effect. It could be specified as an X offset-Y offset pair or a distance-angle pair. They can be used to calculate each other. InDesign also have a concept of global light, which is the angle of the light and is maintained the same for every object of a document. Size Size refers to the size of a transparency effect. It is specified in number of points. For example, a drop shadow with size of 0p5 mains the shadow width is 5 points. Spread Adding spread outsets the object's outline before blurring, so the effect seems bolder. Spread is expressed as a percentage of the blur width. Typically, spread is for outer effects, Spread is the percentage of the size or blur width that is simply outset rather than tapered off. For example, for a drop shadow with a blur width of 10 points and a spread of 0%, you get 10 points of blur. If the spread is 50%, however, you get 5 points of outset and 5 points of blur. If the spread is 100% you get 10 points of outset and no blur. 266 Graphics Fundamentals Transparency effects Noise Random noise can be added to the transparency effect, to give it a rougher appearance. Choke Choke is conceptually the same as spread, but for effects that go “inward,” like inner glow. For example, an inner glow with size 10 points and spread 50%, you get 5 points of inset and 5 points of blur. Feather width Feather width is conceptually the same as size, simply the total amount of inset applied. For example, if you have 10 points of width, the feather extends from the edge of the object to 10 points inside the object. For directional feather, you can specify width in four directions. Basic transparency Basic transparency is an effect that lets the viewer see through an object. The Transparency panel in the user interface allows end users to specify the transparency attributes of selected page items, including blending mode, opacity, whether these should be isolated, and whether knockout is required. Transparency in group items A group item is a collection of one or more page items. Transparency can be applied to a page item or a group item. Transparency groups are constructs to work around real-world problems involving grouped transparent objects. The application allows the assignment of opacity, knockout, and isolation properties to transparency groups (i.e., collections of page items). These group properties determine how a group of page items interact transparently with the backdrop. It also is possible to specify knockout and isolation properties for one page item. Group attributes combine with those of the objects in the group. For example, if objects have 50% opacity and the group has 50% opacity, the resulting opacity of the composited objects is equivalent to an object with 25% opacity. These group properties are independent of, and in addition to, the opacities and blending modes of the individual objects. The objects interact with each other and the backdrop using their individual opacity and blending modes. The group opacity and group-blending mode do not affect the interaction of the individual objects with each other, but they do affect the interaction of these objects with the backdrop. Knockout groups A knockout group is a group whose individual elements do not interact with each other but do interact with the backdrop. The objects within the group paint opaquely over each other, but compositing occurs with the initial backdrop data. An example in which this is useful is a group that consists of the fill and the stroke of a path. If the group is not a knockout group, there is an interaction of the fill and stroke in the region they have in common, which often is undesirable. Instead, the desired effect is to have the stroke opaquely cover the fill in the common overlap, and to have each interact with the backdrop with respect to their individual opacities and blending modes. Figure 102 shows a comparison of transparency effects with and without knockout groups. Graphics Fundamentals 267 Graphics Fundamentals Transparency effects FIGURE 102 Knockout groups Transparency without knockout group Transparency with knockout group Isolated groups An isolated group is a group whose individual elements do not blend with the backdrop independently but do blend with the backdrop as a group. An isolated group can be represented by its group object of color and opacity values. By definition, an isolated group can be represented by color and opacity values that are independent of the backdrop into which it is to be composited. Drop shadow In the real world, drop shadow is generated when light is blocked by an object. As represented in graphics, drop shadow is a blurred representation of the shape of an object, offset by a userspecified distance and drawn below the object. The parameters that control a drop shadow include the ones listed in Table 59. TABLE 59 Drop-shadow parameters 268 Parameter Description Blending mode See “Blending mode” on page 265. Noise See “Noise” on page 267. Object-knockout shadow Object does not interact with shadow. Opacity See “Opacity” on page 265. Position See “Position” on page 266. Shadow honors other effects Shadow can be the result together with other transparency effects. Graphics Fundamentals Transparency effects Parameter Description Size See “Size” on page 266. Spread See “Spread” on page 266. Inner shadow Inner shadow is very similar to drop shadow. It adds a shadow that falls just inside the edges of the object, giving the object a recessed appearance. The parameters that control an inner shadow effect are like those of drop shadows (see Table 60). TABLE 60 Inner-shadow parameters Parameter Description Blending mode See “Blending mode” on page 265. Opacity See “Opacity” on page 265. Position See “Position” on page 266. Size See “Size” on page 266. Noise See “Noise” on page 267. Choke See “Choke” on page 267. Outer and inner glow Glow is a graphic effect that makes an object appear to shine as if with intense heat. Outer glow refers to the glow effect applied to the outside edges of the object; inner glow refers to the glow effect applied to the inside edges. The parameters that control outer glow are listed in Table 61. TABLE 61 Outer-glow parameters Parameter Description Blending mode See “Blending mode” on page 265. Opacity See “Opacity” on page 265. Technique The method to produce angled corners. You can get a smooth/rounded effect (softer) or a mitered effect (precise). Size See “Size” on page 266. Noise See “Noise” on page 267. Spread See “Spread” on page 266. The parameters that control inner glow are listed in Table 62. Graphics Fundamentals 269 Graphics Fundamentals Transparency effects TABLE 62 Inner-glow controlling parameters Parameter Description Blending mode See “Blending mode” on page 265. Choke See “Choke” on page 267. Noise See “Noise” on page 267. Opacity See “Opacity” on page 265. Size See “Size” on page 266. Source Indicates the “polarity” of the glow. “Center” means the center of the object glows and the edges do not. “Edge” means the opposite. Technique The method to produce angled corners. You can get a smooth/rounded effect (softer) or a mitered effect (precise). Bevel and emboss The bevel and emboss effect is a kind of simulation of how an object would look if it were “puffed up” into the third dimension. The parameters that control bevel and emboss are listed in Table 63. TABLE 63 Bevel and emboss parameters 270 Parameter Description Style A choice of inner bevel, outer bevel, emboss and pillow emboss. Direction Indicates whether the object appears to be “sunken” or “raised.” Technique Simulate effect made with smooth, chisel hard and chisel soft. Soften The amount of blurring, more or less, that is applied to the beveled result. This softens the effect so your bevel is not so harsh. Size Width of the effect. See “Size” on page 266. Depth Determines the intensity or sharpness of the bevel. Angle The direction in the page-plane of the light source. Altitude The angular distance above the page plane. Highlightblending mode See “Blending mode” on page 265. Highlight opacity See “Opacity” on page 265. Shadow-blending mode See “Blending mode” on page 265. Shadow opacity See “Opacity” on page 265. Graphics Fundamentals Transparency effects Satin Satin applies interior shading that creates a satiny finish. Table 64 lists its controlling parameters. TABLE 64 Satin parameters Parameter Description Blending mode See “Blending mode” on page 265. Opacity See “Opacity” on page 265. Angle The direction of the light to create effect. Distance The distance of the light to satin effect. Size See “Size” on page 266. Feather effects Feather is a graphic effect that allows designers to create a smooth edge around a frame. InDesign support three types of feathers: basic, directional, and gradient. The parameters that control a basic feather effect are listed in Table 65. Directional-feather effect feathers only on selected sides of an object and takes additional parameters, listed in Table 66. Gradient effect creates a linear or radial gradient of opacity around an object and allows parameters to define a gradient, like gradient stops, gradient type and angle,; see Table 67. TABLE 65 Basic feather parameters Parameter Description Feather width See “Feather width” on page 267. Corners Diffused, sharp, or rounded. Choke See “Choke” on page 267. Noise See “Noise” on page 267. Feather noise is added only to the feather region. TABLE 66 Directional-feather parameters Parameter Description Angle The direction of the feather. Choke See “Choke” on page 267 Feather widths See “Feather width” on page 267. Noise See “Noise” on page 267. Shape First edge only, leading edges, or all edges. Graphics Fundamentals 271 Graphics Fundamentals Transparency effects TABLE 67 Gradient-feather parameters Parameter Description Gradient stops Defines the gradient Gradient type Linear or radial gradient Angle The direction of the gradient Flattening PostScript and PDF 1.3 have no representation of transparency information. To print or export spreads with transparent information, it is necessary to generate nontransparent representations of the effects of transparency; this is known as flattening. In some cases, the interactions may be among areas of solid color, in which case they can be replaced by a solid color in each region of interaction. If images are involved, a composite image must be calculated that reflects the contributions of the objects being composited, including any solid-color areas. Dealing with text and gradients requires the application of additional rules. If a section of the page is particularly complex, it can be faster to rasterize the area than to try to calculate all the interactions; the flattener user interface supports this feature. The flattener is an Adobe core technology. Its implementation comes from the Adobe Graphics Manager (AGM) library, and it is used in other Adobe applications that support transparency within vector graphics, such as Illustrator. The end user has a degree of control over how the flattener is used. The Print dialog box has an option to parameterize the flattener. The user may choose flattener presets and specify, for example, that high quality is preferred over high speed. There is a trade-off between precision of results and resources used. The lower the resolution, the quicker and less memory-intensive the calculation. Flattening is a complex and potentially resource-expensive process. Various optimizations are required to implement transparency effectively, such as caching high-resolution images to file, to ensure that the memory requirements are minimized. There also are complexities introduced by OPI image substitution, because printing with transparency requires that embedded files write graphic primitives into the output stream. Transparency data model Transparency features are complicated, but the principles of their implementation are not. Basically, transparency implementation involves the following related aspects: 272 z Graphic attributes used to specify states and parameters of transparency effects z Page-item adornments used to draw transparency effects z Service providers and drawing-event handler to participate in the printing process that flattens the transparency before printing Graphics Fundamentals Transparency effects The boss classes responsible for transparency behavior are delivered mainly by the Transparency plug-in. The user interface to the effects is supplied by the TransparencyUI plug-in. Transparency information is represented by graphic attributes, and transparency is rendered to a device through page-item adornments. Defining transparency: graphic-attribute bosses Transparency effects are defined programmatically as a set of graphic attributes. These attribute boss classes derive from kGraphicsAttrBoss and aggregate a collection of interfaces that set and get a variety of graphic-attribute data types. For general information about graphic attributes, see “Graphic attributes” on page 256. For a summary of the transparency=attribute boss structure, see “Transparency-attribute boss structure” on page 273. Transparency-attribute targets Transparency effects can be applied to the object, stroke, fill, or content. They are called transparency targets. Accordingly, transparency attributes can be categorized into different targets. Attribute targets are defined as enums in IXPAttributeSuite::AttributeTarget. Transparency-attribute groups Each transparency effect has a set of attributes to represent the parameters that control the effect. Accordingly, transparency attributes can also be categorized into groups. Each group corresponds to each transparency effect. Transparency-attribute groups are defined as enums in IXPAttributeSuite::AttributeGroup. Transparency-attribute data types and values Different transparency attributes hold different types of data. The IXPAttributeSuite::AttributeDataType enum defines all possible data types a transparency attribute can have. IXPAttributeSuite::AttributeValue is a class that can hold values for any of the attributes. It serves as a generic container for get and set functions. Transparency-attribute boss structure Transparency-attribute bosses are organized as a three-level inheritance. The most generic level is the kGraphicsAttrBoss. This implies transparency attributes work and can be manipulated the same way as any other graphic attributes. The next level is attribute groups. These attribute group bosses inherit from kGraphicsAttrBoss and aggregate the IID_IOBJECTSTYLEATTRINFO interface with the kXPAttrInfoImpl implementation. These groups correspond to the transparency effects; see Table 68. TABLE 68 Transparency-attribute groups Group-attribute boss Transparency effect kDropShadowAttrBoss Drop shadow kVignetteAttrBoss Basic feather kXPAttrBoss Basic transparency Graphics Fundamentals 273 Graphics Fundamentals Transparency effects Group-attribute boss Transparency effect kXPBevelEmbossAttrBoss Bevel and emboss kXPDirectionalFeatherAttrBoss Directional feather kXPGradientFeatherAttrBoss Gradient feather kXPInnerGlowAttrBoss Inner glow kXPInnerShadowAttrBoss Inner shadow kXPOuterGlowAttrBoss Outer glow kXPSatinAttrBoss Satin The bottom level has the real transparency attributes that define every transparency. For example, kXPBasicOpacityAttrBoss, kXPStrokeBlendingOpacityAttrBoss, kXPFillBlendingOpacityAttrBoss, and kXPContentBlendingOpacityAttrBoss inherit from kXPAttrBoss and aggregate the IID_IGRAPHICATTR_REALNUMBER interface. They define the opacity attribute of basic transparency for object, stroke, fill, and content targets, respectively. Transparency-attribute types There are about 400 transparency attributes. You may still access them in the general graphicattribute way; however, the InDesign API also provides utility functions in IXPAttributeUtils to manipulate transparency attributes more effectively. Part of that is the concept of transparencyattribute types. Transparency-attribute types are defined as enums in IXPAttributeSuite::AttributeType. These enums are divided into segments according to transparency targets and transparency groups. The BASE_XP_ATTR(t,x) macro generates the base index of the segment. For example, if you want to know the enum value of the first transparency attribute for controlling inner shadow on the stroke of an object, use kStrokeInnerShadowBaseID + 1. kStrokeInnerShadowBaseID is calculated as BASE_XP_ATTR(kTargetStroke, kGroupInnerShadow). A transparency-attribute type has a one-to-one mapping to transparency-attribute boss. You can translate between AttributeTypes and attribute-boss ClassIDs using the GetAttributeClassID and GetAttributeFromClassID methods on IXPAttributeUtils. Drawing transparency: adornment bosses To create a transparent rendering for an object, add an IAdornmentShape implementation to the adornment boss class that provides the behavior for the object. The kBeforeShape and kAfterShape flags specify when to draw in response to the IAdornmentShape::GetDrawOrderBits method. The IAdornmentShape::GetPaintedBBox method specifies the adornment bounding box. Bound of the outer effects are larger than the object’s bounds. Table 69 lists the adornment bosses responsible for drawing transparency effects. One adornment boss can draw multiple effects. The primary reason we do not have one adornment for every effect is to limit the total number of adornments of a page item, for performance reasons. 274 Graphics Fundamentals Transparency effects TABLE 69 Boss classes that aggregate IAdornmentShape Boss-class name Description kXPDropShadowAdornmentBoss Draws knockout drop shadows and outer glow. kXPPageitemAdornmentBoss Draws blending and non-knockout drop shadows. kXPVignetteAdornmentBoss Draws basic feather, directional feather, and gradient feather. kXPInnerEffectsAdornmentBoss Draws inner effects, like inner shadow, inner glow, bevel and emboss, and satin. Printing transparency: flattening Before transparency is printed, transparency effects must be flattened. You can choose different flattener presets to represent transparency using non-transparency representation, then print the result as normal page items. Managing flattener presets Flattener presets are represented by kXPFlattenerStyleBoss. The key interface is IFlattenerSettings, which defines settings of presets, directly corresponding to the Flattener Preset Options dialog box. The flattener preset is an application-wide preference. The IFlattenerStyleListMgr interface is aggregated on kWorkspaceBoss and is responsible for managing all flattener presets. As with other general presets, like print presets, the IFlattenerStyleListMgr implementation hooks flattener presets into the generic presets dialog and provides an entry point for adding, deleting, and editing flattener presets with respective commands. The kSpreadBoss also aggregates IFlattenerSettings, which allows the spread to override the flattener settings for a specific spread. Printing-related bosses Transparency participates in the printing process by iterating spreads for pages containing transparency effects that require flattening. With these bosses, the print command can examine transparency use, setting up viewport attributes and so on. Together with drawing in the spread and page item, InDesign can achieve results that appear as if there are transparency interactions, even though these are accomplished through flattened, opaque, drawing instructions. See Table 70. Graphics Fundamentals 275 Graphics Fundamentals Data model for drawing TABLE 70 Printing-related boss classes Boss-class name Description kXPGatherProviderBoss A document iterator provider that gathers document-wide use of transparency. kXPPrintSetupServiceBoss Implements print services to set up global color profiles. kXPDrwEvtHandlerBoss Transparency start-up and shut-down. Hooks transparency into the draw manager. Data model for drawing Presentation views Drawing documents to the screen really means drawing to an application-layout presentation, which is a platform-independent construct containing layout widgets that display the contents of the document. Layout presentation is represented by kLayoutPresentationBoss, with the key interface IDocumentPresentation. Note that kLayoutPresentationBoss is inherited from kWindowBoss; however, it is very important not to use the IWindow interface for any layout-presentation operation. Instead, always use IDocumentPresentation for operations like minimizing the view. The IWindow on a kLayoutPresentationBoss is only for internal use. There may be several layout presentations open at the same time; these can be hosted in one operating-system window as tabbed document presentation views, or each layout presentation can be hosted inside its own operating-system window. In addition to the layout presentation, there are other windows/view containers in InDesign. Dialog boxes and pop-up tips are application windows and are represented by the platformindependent kWindowBoss object. The panel container, often referred to as palette, is represented by a PaletteRef. For more detail on these interfaces and their responsibilities, see the API reference documentation. To summarize, the application manages two main categories of views: z Document presentations have a document associated with them and display the content of the document. They also are referred to as layout presentations. A document presentation may not always correspond to a standalone operating-system window, because an operating-system window can have many document presentations in it. Note, however, that “window” is still being referred to throughout this document, because that is still a commonly accepted term for the view to a document. z User-interface windows/palettes are used for dialog boxes, panels, and other types of windows that do not have documents associated with them. Most of the detail in the remainder of this section concerns drawing a layout. 276 Graphics Fundamentals Data model for drawing Graphics context Drawing requires a graphics context. When page items are called to draw, they are provided with a GraphicsData object, which contains a pointer to an InDesign graphics context. Using the application’s graphics context, page items can perform platform-independent drawing to several of device contexts: screen, print, or PDF. The graphics context for application drawing is described by an object derived from IGraphicsContext, an abstract-data container interface. This interface is not aggregated on boss classes, nor is it derived from IPMUnknown. Instead, implementations of IGraphicsContext are specialized for different drawing devices. A graphics context is instantiated based on a viewport boss object (see “Viewport” on page 277), IControlView interface pointer, and update region. Several important pieces of information are stored in the graphics context object, including the following: z The current rectangular clip region for the drawing port. z The transform for mapping content to drawing device coordinates. The transform describes the relationship of the content coordinates to the drawing-device coordinates. For screen drawing, the drawing device is a window. The transform is based on the IControlView implementation supplied at the time of the graphics-context instantiation. During a normal screen-drawing sequence, this is the IControlView implementation on the kLayoutWidgetBoss that instantiates the graphics context, so the transform is initialized to be pasteboard to the application-window coordinates. During the drawing sequence, this transform is modified to represent parent-window coordinates. For a description of coordinate systems related to drawing, see the “Layout Fundamentals” chapter. Screen draws do not paint the entire document and then copy only a portion of it to the window. Instead, only the region of the window marked invalid is redrawn. The clip region stored in the graphics context is applied like a mask, discarding any drawing outside the clip bounds. During a drawing sequence, the clip represents the update region in the window and is stored in window coordinates. For drawing to the screen, AGM is used to provide the graphics context. An offscreen context is used for drawing, to facilitate a smooth, flicker-free screen update. The drawing code renders off-screen, and the result of the completed drawing is subsequently copied to the screen. For more details, see “Offscreen drawing” on page 284. The use of off-screen contexts is transparent to page items when they draw. The graphics context provided to the page item hides these implementation details. Viewport The application’s platform-independent API for drawing is provided by the viewport. Page items use the IGraphicsPort interface on the viewport boss object for drawing. The viewport boss object does not draw directly to the platform window; instead, the viewport boss object draws through the AGM, which is specialized for the type of drawing device (for example, PostScript printing or the screen). The specialization is transparent to clients of the graphics context and the viewport boss object. Graphics Fundamentals 277 Graphics Fundamentals Dynamics of drawing A viewport boss object operates as a wrapper between the drawing client (often a page item) and the underlying AGM code that defines the graphics context for the output device. There are several different types of viewport boss classes, each tailored to a particular type of drawing output. For a list of relevant boss classes and the responsibilities of the interfaces on the boss classes, see the API reference documentation for IViewPort. For example, kWindowViewPortBoss is used for drawing to application windows. Dynamics of drawing Drawing the layout Layout drawing is the process of drawing page items to the layout presentation. Layout is described in depth in the “Layout Fundamentals” chapter. For more detail on how individual page items are drawn, see “Drawing page items” on page 281. Invalidating a view InDesign drawing occurs in response to invalidation of a view, or region. Although InDesign provides platform-independent APIs for invalidating a view, the APIs simply forward the invalidation to the operating system. The invalidation state is maintained by the operating system, which generates update events to the application. Invalidation can be caused by changes to the model (persistent data in a document) or direct invalidation. Both use the same mechanism to invalidate a view. Changes to the model are broadcast to interested observers with regular or lazy notification. For example, the application uses an observer on the layout widget to monitor changes to page items in the layout. When the observer receives notification of a change, it asks the subject of the change to invalidate a region based on its bounding box. Views can be directly invalidated by using the ILayoutUtils::InvalidateViews method. The collaboration of boss objects is shown in Figure 103. 278 Graphics Fundamentals Dynamics of drawing FIGURE 103 Boss collaboration when invalidating a view ILayoutUIUtils * InvalidateViews «boss» kLayoutWidgetBoss * * ILayoutController::InvalidateContent «boss» kWindowViewportBoss * * IWindowPort::InvalRgn Platform invalidation * The ILayoutUtils::InvalidateViews method uses a document pointer to locate the views for a document. For each view, the method gets the ILayoutController interface on the kLayoutWidgetBoss and calls ILayoutController::InvalidateContent, which creates an invalidation region equal to the view’s window. The invalidation region is passed to the IWindowPort::InvalRgn method on the IWindowPort interface of the kWindowViewPortBoss corresponding to the window. This method then passes the invalidation region to the operating system. The invalidation region is then accumulated by the operating system, which generates a paint message. The operating system sends an update message (event) to the InDesign event dispatcher, where the message is wrapped in a platform-independent class and routed to the event handler on the appropriate window. The window’s event handler calls indirectly the IControlView::Draw method. At that point, the drawing sequence begins following the pattern for drawing a widget hierarchy; Draw uses the IPanelControlData interface to locate each of its children and call Draw on the child’s IControlView interface. This means the kLayoutPanelBoss is called to draw, and it iterates each of its child widgets (scroll bars, the layout widget, rulers, etc.). The drawing sequence concludes with validating the contents of the window. This completes the update cycle, from invalidation to redraw. Layout drawing order Layout presentations are updated in several steps that allow better performance and the opportunity to interrupt the drawing. Good performance is achieved by specializing the drawing Graphics Fundamentals 279 Graphics Fundamentals Dynamics of drawing operations according to the view’s z-order, whether the invalidation is due to a selection change or because all objects changed. At the level of the kLayoutWidgetBoss, several decisions are made behind the scenes for the sake of drawing performance. The IControlView implementation on the kLayoutWidgetBoss chooses what to draw based on the window’s z-order, the selection, and the update region. Foreground and background drawing If the window is the front view, two views may be drawn: a background view containing all objects and a foreground view containing only the decorations for the selection. Offscreen graphics contexts are created and cached for both views (see “Offscreen drawing” on page 284). If the update region overlaps the window or the current front view was not the last view to have been drawn, the background view is redrawn. If the selection is not empty, the foreground view also is redrawn. Based on the above rules, the kLayoutWidgetBoss IControlView filters the visible spreads and calls their IShape::Draw methods through the InDesign draw manager. This filtering means page items are not guaranteed to be called for a screen draw. The background draw then propagates through the layout hierarchy, as described in “Spread-drawing sequence” on page 307. After the background draw is complete, if the selection is empty, the background image is copied to the window and the draw is complete. If the selection is not empty, the foreground draw starts by copying the background image to the foreground offscreen context. The selection is drawn to the foreground, then the foreground image is copied to the window. The use of foreground and background draws means a page item could be called twice during a redraw: the first call to IShape::Draw in the order of the layout hierarchy for the background draw, and the second call to IHandleShape::Draw in the order of the selection list for the foreground draw. If the window is not the front view, a more abbreviated drawing sequence takes place. Both the document items and the selection are drawn to a foreground offscreen context, and it is copied to the screen. Z-order Z-order is the order (depth) of page item objects in the direction perpendicular to the screen. Z-order determines which object or part of an object is visible to the user. InDesign handles three levels of z-order: 1. Window z-order — InDesign windows may overlap. 2. Layer order — InDesign documents are layered. InDesign draws page layers first, then other document layers. For more information, see the “Layers” section of the “Layout Fundamentals” chapter. 3. Page item z-order — On the same layer, page items are ordered according to their positions in the parent object’s hierarchy. The child with index 0 is drawn first; the child with the greatest index is drawn last. For more information, see the “Documents and the Layout Hierarchy” section of the “Layout Fundamentals” chapter. 280 Graphics Fundamentals Dynamics of drawing NOTE: Do not confuse z-order with foreground and background drawing. Z-order controls what is visible to the viewer, whereas foreground and background are just bitmaps for speeding up rendering. Draw manager Conceptually, kLayoutWidgetBoss calls each spread to draw. In reality, kLayoutWidgetBoss calls through the InDesign draw manager. The draw manager is an interface that exists on each viewport and is used to set clipping areas and initiate the drawing of any page element and its children to that viewport. The draw manager can be used for drawing to the screen, PDF, and print. Drawing in InDesign occurs on a spread-by-spread basis and is hierarchical. Without a service like the draw manager, it would be hard to change the behavior of drawing in a subhierarchy. Optionally, you can create a kDrawMgrBoss and use the IterateDrawOrder method, which allows clients to iterate the document in the same manner as drawing, calling a clientprovided callback routine for every page item in the hierarchy, but without a graphics context. Funneling all drawing activity through the draw manager provides three important features for changing the behavior of drawing operations: z Clipping of areas to be drawn. z Filtering of items to be drawn. z Interrupting a drawing sequence. Clipping and filtering provide a means to select items for the draw based on regions. The draw manager maintains the current values for the clip and filter regions. Interruption of the drawing sequence relies on the broader mechanism of drawing events. As items draw, they broadcast standard messages that announce the beginning and end of discrete drawing operations. Drawing events are received by special handlers that register interest in particular types of messages, and each drawing-event handler has the opportunity to abort the draw at that point. Clients of the draw manager (like the layout widget) install a default drawing-event handler. The draw manager provides services for hit testing, iterating the drawing order, and drawing. Detail about how spreads are drawn is described in “Spread-drawing sequence” on page 307. Drawing page items When page items are called to draw, they are passed information about their drawing context, including a GraphicsData object and IShape drawing flags (e.g., kPatientUser). For more information, see the API reference documentation for these types. Page items use this information to perform their drawing operations. The IGraphicsPort interface is the InDesign interface for drawing and is aggregated on all viewport boss classes. The IGraphicsPort interface is used by all drawing interfaces on a page item, regardless of the output device. The viewport settings can be modified using IGraphicsPort methods. The IGraphicsPort::gsave and IGraphicsPort::grestore methods effectively push the current port settings onto a stack and pop the old settings when desired. These methods are used to save the current port settings when setting the port’s transform to a new space. For example, when a page item is called to Graphics Fundamentals 281 Graphics Fundamentals Dynamics of drawing draw, it should save the port settings, set the port to its inner coordinate space, draw, and restore the port before returning. The IGraphicsPort implementations provide methods very similar to PostScript graphics operators. These methods support drawing primitives, port-transformation manipulation, and changing port-clip settings. For a complete list of the methods, see the API reference documentation for IGraphicsPort.h. Line-drawing methods like IGraphicsPort::lineto, IGraphicsPort::moveto, IGraphicsPort::curveto, IGraphicsPort::closepath, IGraphicsPort::fill, and IGraphicsPort::stroke are available. If a path is defined in the port, it can be discarded using the IGraphicsPort::newpath method. These methods are demonstrated in the “Graphics” chapter of Adobe InDesign CS4 Solutions. Control over the color space, color values, gradient, and blending modes also is available through IGraphicsPort methods. See Table 71 for a list of interfaces for drawing page items. TABLE 71 Interfaces for basic page-item drawing Interface Function IGraphicStyleDescriptor Renders graphic attributes. IHandleShape Renders selection handles. Called during foreground drawing. IPageItemAdornmentList Lists adornments for a page item. IPathPageItem Renders low-level draws for path, fill, and stroke. IShape Renders path, fill, and stroke. Called during background drawing. IShape, IPathPageItem, and IHandleShape are directly involved in drawing a page item. IShape is the main interface for drawing the page item and is called when the entire page item needs to be rendered. Path-based items like spline bosses also have the IPathPageItem interface to handle the details of drawing their paths. IHandleShape is called when a page item is in the selected state and is used for drawing the decorations that denote selection. PathHandleShape is responsible for drawing path-selection handles. IGraphicStyleDescriptor maintains the graphic attributes for the page item. The drawing process sets graphics port settings based on various graphic attributes. IPageItemAdornmentList maintains a list of adornments for the page item. Adornments are drawn with the page item. This interface provides a means to enhance or decorate a page item’s appearance. For more detail, see “Extension patterns” on page 289. IShape is responsible for providing the drawing, hit testing, drawing-order iteration, and invalidation functions for page items. This interface is responsible for rendering a page item and is used during background draws to create the path, fill, and stroke of an object. For details, see its API reference documentation. There are partial implementation classes like CShape and CGraphicFrameShape in the public API. For details, see the API reference documentation. 282 Graphics Fundamentals Dynamics of drawing For details on the drawing sequence for a page item, see “Drawing sequence for a page item” on page 310. The IHandleShape interface The IHandleShape interface is responsible for drawing and hit testing for a page item’s selection handles. This interface is defined in the abstract base class in IHandleShape.h. As with the IShape class, the IHandleShape drawing sequence includes extensibility points in the form of adornment calls. For more detail, see “Extension patterns” on page 289. For more detail on its responsibilities, see the API reference documentation on IHandleShape. Most page items (such as kSplineItemBoss) that aggregate IHandleShape (with the ID IID_IHandleShape interface) also have another implementation of IHandleShape which is based on PathHandleShape (with the ID IID_IPATHHANDLESHAPE interface). The implementation based on PathHandleShape inherits from the same superclass as IHandleShape; therefore, it has exactly the same public interface. The purpose of this interface is to draw pathselection handles. Observe the difference in the user interface by switching between the Selection and Direct Selection tools. The IPathPageItem interface The IPathPageItem interface encapsulates the specialized drawing functions for path-based page items. This class provides methods for operations like stroke, fill, clip, and copying a path to the graphics port. The CGraphicFrameShape class delegates these specific draw operations to the IPathPageItem class. In this class, graphic attributes are used to control the appearance. The IPathPageItem::Stroke method first calls IPathPageItem::Setup, which initializes a set of default stroke properties and then tries to get the stroke graphic attributes, like stroke weight and a ClassID for a path stroker. The path stroker is a service provider that delivers the kPathStrokerService. The IPathPageitem::Stroke method then uses the stroke graphic attributes and path stroker to actually create the stroke. Drawing in user-interface widget windows A user-interface widget is any descendant of kBaseWidgetBoss. Drawing in a user-interface widget window—such as a palette, dialog box, or panel—is like drawing to the layout presentation. Instead of calling the draw method of the layout-control view, palette drawing calls IControlView::Draw methods of various IControlView implementations. The first stage in creating an owner-drawn panel is constructing an AGMGraphicsContext object from the IControlView::Draw parameters and obtaining an IGraphicsPort from the graphic context. Next, set colors and draw the items. This can be done through the IInterfaceColors interface, aggregated on kSessionBoss. There are a few standard interface colors common to drawing items in user-interface windows. User-interface colors are defined in InterfaceColorDefines.h. Next, set the color of the graphics port and draw items. Graphics Fundamentals 283 Graphics Fundamentals Dynamics of drawing Each each widget actually is a window, so the PMRect value from IControlView::GetFrame represents the coordinates of the widget in its parent widget. An IControlView::MoveTo(0,0) call is convenient for transforming the coordinates. You can draw lines, boxes, and so on as you normally draw in the layout presentation, using the methods of IGraphicsPort. For drawing PMString, InDesign provides utility methods on the StringUtils class (DrawStringUtils.h) that let you measure a PMString and draw strings directly. For more details, see the API reference documentation. For an example of an owner-drawn panel, with a custom IControlView::Draw implementation, see the SDK sample PanelTreeView in <SDK>/source/sdksamples/paneltreeview, and inspect PnlTrvCustomView.cpp. Offscreen drawing Purpose of offscreen drawing An offscreen drawing is simply a bitmap. The technique of offscreen drawing has been used for years by various applications to reduce screen flicker and improve performance when drawing to the screen. Mac OS X actually creates a separate offscreen buffer for each window, such that when an application tries to draw to a window, it actually is drawing to the offscreen buffer. The operating system then periodically transfers its offscreen buffer to the actual screen. This process is done at the operating-system level and decreases the number of cases in which InDesign needs to draw offscreen on Mac OS X. Drawing layout offscreen Offscreen drawing is used just about any time the layout presentation needs to update. InDesign maintains an offscreen representation of the layout presentation with everything except the current selection highlighting. Hence, when the selection changes, InDesign can very quickly redraw the screen from the offscreen buffer, followed by drawing the new selection. The biggest area where offscreen drawing is used is the layout-control view. Drawing background and foreground in layout-control view is discussed in “Layout drawing order” on page 279. What must be emphasized here is that drawing the layout does not really draw to the screen directly; instead, drawing the layout actually draws offscreen. Corresponding to background and foreground drawing, there are background offscreen buffers and foreground offscreen buffers. The background offscreen representation in InDesign is the offscreen buffer maintained by each layout view, containing everything except current selection highlighting. Each layout view has its own offscreen buffer. The background offscreen buffer is invalidated by querying for the ILayoutController of the IControlView interface for the layout and calling ILayoutController::InvalidateContent. InDesign can be told to update a layout without dirtying the background offscreen buffer, by querying for the ILayoutController of the IControlView interface for the layout and calling ILayoutController::InvalidateSelection. Palettes and dialog boxes are responsible for their own offscreen representations. In general, most panels do not use offscreen drawing; however, a few user-interface windows, like the Navigator panel, maintain their own offscreen representations. As mentioned above, Mac OS X 284 Graphics Fundamentals Client APIs provides offscreen buffers for all windows, so offscreen drawing on Mac OS X is not necessary if the goal is simply to avoid flicker. Offscreen data Drawing offscreen is drawing to the kOffscreenViewPortBoss. Besides other interfaces that are involved in drawing, one of the most important interfaces on kOffscreenViewPortBoss is IOffscreenPortData. This is the interface that stores a reference to the offscreen bitmap and distinguishes kOffscreenViewPortBoss from other viewports. An offscreen bitmap is wrapped in the platform-independent IPlatformOffscreen. You can get and set bitmaps with IOffscreenPortData; however, you are not allowed to create bitmaps directly. Instead, you may want to aggregate an IOffscreenViewPortCache interface on the control-view boss class, so you can query background and foreground viewport data. For more information, see the API reference documentation for IPlatformOffscreen, IOffscreenPortData, and IOffscreenViewPortCache. Snapshots A snapshot is a record of a part of the document view at a specific instant. SnapshotUtilsEx draws items into a memory-based graphics context, creating a bitmap (snapshot) that can be exported to a stream in several formats, like JPEG, TIFF, or GIF. SnapshotUtilsEx also creates its own offscreen bitmap and uses an IDrawMgr to walk the IHierarchy and draw specific page items to the offscreen buffer; however, the internal implementation is different. Like layout offscreen, the viewport SnapshotUtilsEx interacts with is kAGMImageViewportBoss, the bitmap it draws to is of type AGMImageRecord defined in GraphicsExternal.h, and it uses IAGMImageViewPort to manipulate the bitmap. SnapshotUtilsEx does not interact with the layout's offscreen representation in any way. SnapshotUtilsEx is very useful for creating proxy images of documents, since it uses the same draw manager to draw page items in memory, a much faster way. Sample code in the Snapshot sample plug-in and in SnpCreateInddPreview.cpp demonstrates the use. The sample code in the SDK still uses SnapshotUtils. We recommend using the more recent SnapshotUtilsEx. Client APIs Path-related client APIs High-level APIs provided to manipulate paths are summarized in Table 72. For details about them, see the API reference documentation. Graphics Fundamentals 285 Graphics Fundamentals Client APIs TABLE 72 Path and graphic page-item APIs API Description IPathPointScriptUtils Utility methods related to path point scripting (called by script providers). IPageItemTypeUtils Utilities to get the type of a page item. IPathUtils Path manipulations. ISplineUtils Utilities for spline-item manipulations. IPathInfoUtils Analyzes whether a list of PathInfo object forms a point or straight line. IPathPointUtils Utility methods related to path point transformations. IPathOperationSuite Manipulates paths on selected page items, including compound paths. Includes path-finder operations. IConvertShapeSuite Converts selected page items to a new shape. Graphic page-item client APIs APIs provided to manipulate graphics are summarized in Table 73. For details about them, see the API reference documentation. TABLE 73 Graphic page-item APIs 286 API Description IFrameContentSuite Selection suite interface for content fitting and framecontent conversion. IFrameContentFacade Facade for content fitting and frame-content conversion. IFrameContentUtils Utility interface for determining various aspects of frame contents. IClippingPathSuite Gets and sets clipping path for selected graphics items. ITextWrapFacade Facade for manipulating text wrap. IDisplayPerformanceSuite Changes display performance settings for selection. IImageObjectSuite Accesses image layers. IImageFacade Facade for getting image information. IJPEGExportSuite Exports selection to JPEG file format. ISVGExportSuite Exports selection to SVG file format. Graphics Fundamentals Client APIs Key color-related client APIs Interfaces provided to manipulate color, swatch, ink, and color management objects are summarized in “Color-related APIs” on page 287. For details about them, see the API reference documentation. TABLE 74 Color-related APIs API Description IGradientAttributeSuite A selection suite interface. Provides gradient attribute– related operations that apply to the application defaults, document defaults, text, layout, and tables. ISwatchUtils Utility interface to manipulate swatches. For example, this interface can be used to acquire the active swatch list, retrieve or instantiate new, persistent, rendering boss objects, and modify the properties of the swatch list. IUIColorUtils Utility interface for dealing with user-interface colors. IInkMgrUtils Utility interface for managing inks. For example, this interface can be used to acquire the active ink list and retrieve information about name, type, ink alias, and corresponding swatches of a spot ink. IInkMgrUIUtils Utility interface, mainly for calling the ink-manager dialog box. IColorSystemUtils Utility interface for color-rendering objects. For example, this interface can be used to get color space and color components of a given color swatch. ICMSAttributeSuite A selection suite interface. Provides color-management functionality for the selected image page item, like getting or applying color profile or rendering intent. ICMSUtils Utility interface for the color-management system. For example, this interface can be used to obtain CMSSettings and ProfileList. Provides wrappers for color-management commands. ICMSManager A manager interface that provides a generic wrapper around a color-management system (CMS). Access to the CMS typically is done by coordinating between this interface and a data interface for the specific CMS implementation. IColorPresetsManager A manager interface that manages a set of color preset files. For example, load or save a color preset, and get or set working RGB/CMYK profile and CMS policy. Graphics Fundamentals 287 Graphics Fundamentals Client APIs Since color-related objects like colors, swatches, inks, and color profiles are stored in the document or application database, you will need commands to manipulate them. The utility interfaces described above provide a higher-level abstraction that wrap the required commands. For a list of commands, see the API reference documentation. Graphic-attribute client APIs APIs provided to manipulate graphic attributes are summarized in “Graphic-attribute APIs” on page 288. For details about them, see the API reference documentation. TABLE 75 Graphic-attribute APIs 288 API Description IGraphicAttributeUtils Exposes methods that can be used to create lists of attribute overrides and create commands to apply attribute overrides. It also exposes methods to read the graphic attributes of document objects. IGraphicStateUtils Exposes methods to create or process commands to apply overrides, swap stroke and fill, and so on. It also exposes a key method to acquire a reference to the active graphic state, which is discussed in detail in the “Graphics” chapter of Adobe InDesign CS4 Solutions. IGraphicAttributeSuite Selection suite that can be queried for through an abstract selection (kAbstractSelectionBoss). It is aggregated on the concrete selection boss classes connected with application defaults, document defaults, layout, tables, and text. IGraphicAttrProxySuite Selection suite that switches graphic attributes between layout objects and text. IStrokeAttributeSuite High-level attribute suite interface specifically to get and set various stroke attributes. It uses IGraphicAttributeSuite to get and set appropriate data. IXPAttributeSuite Accesses or changes transparency attributes on the selected page items or group items. This header file also defines all transparency-attribute-related enums such as attribute types. IXPAttributeUtils Transparency-attribute-related utility functions IXPAttributeFacade High-level transparency-attribute facade. Defines methods to get and set all transparency attributes. IXPUtils Transparency utility functions. Mainly for flattening. IXPManager Transparency helper functions. Graphics Fundamentals Extension patterns There are command boss classes used to manipulate graphic attributes, graphic style, and graphic state. The utility interfaces described in Table 75 provide a higher-level abstraction that wraps the common commands. For a complete list of provided commands, see the API reference documentation. Extension patterns Custom graphic attributes You can provide custom graphic attributes that extend InDesign function for end users. As explained in “Representation of graphic attributes” on page 258, graphic attributes are applied to page items by adding to a list of attribute boss objects associated with the page item. To define a customized graphic attribute, follow these steps: 1. Create a new boss class for the attribute. The boss class should inherit from kGraphicsAttrBoss. 2. Provide an implementation of the IGraphicAttributeInfo interface. 3. If the graphic attribute value could be stored in an existing data interface, like IGraphicAttrBoolean or IGraphicAttrClassID, add it to the attribute class; otherwise, implement an interface of your own. 4. Provide your own code to initialize and set your attribute data when the attribute is applied to a page item. Code to apply the attribute to a page item also is required. If you implemented a custom graphic attribute, you are likely to use a page-item adornment to decorate the page item based on your graphic-attribute value. For an example, see the TransparencyEffect and TransparencyEffectUI sample SDK plug-ins. Custom path-stroker effects You can provide custom path strokers with your own stroke implementation through a kPathStrokerService. The service provider should provide an implementation of IPathStroker, with IStrokeParameters used for storing parameters for the stroke. See “Path stroker” on page 262. To implement a custom path stroker, follow these steps: 1. Create a new boss class for the service provider (for example k<XXX>PathStrokerBoss). Add a service provider to the boss class (the application-provided kPathStrokerServiceProviderImpl can be re-used), and define your implementation of IPathStroker. 2. Create your implementation of IPathStroker. The interface basically provides methods on how to draw the path on the specific graphic port and hit testing (stroke bounding box, etc.). Graphics Fundamentals 289 Graphics Fundamentals Extension patterns 3. If the implementation of the stroker is complicated, you may aggregate additional interfaces on the boss. InDesign CS4/InCopy CS4 provides a common stroke-parameter implementation of the IStrokeParameters interface. The interface stores information like where a path segment starts and the length of the segment. For details, see the API reference documentation. To change only the dash and gap of a stroke, you do not need a custom stroke implementation. Instead, just apply the appropriate kDashedAttributeValuesBoss attribute. Custom corner effects You can provide a custom corner path with your own corner path implementation through a kPathCornerService. The service provider should provide an implementation of IPathCorner. See “Path corners” on page 263. To implement a custom corner effect, follow these steps: 1. Create a new boss class for the service provider (for example k<XXX>CornerBoss). Add a service provider to the boss class (the application-provided kPathCornerServiceProviderImpl can be re-used), and define your own implementation of IPathCorner. 2. Create your implementation of IPathCorner. The interface basically provides drawing methods from three points on the corner. For detailed definitions of the pointers, see the API reference documentation of the interface. The three points are calculated by a private method not included in the SDK from the stroke path and corner size. You need to provide only the method for creating the corner effect using these points. 3. Determine the size of the corner, and apply kGraphicStyleCornerRadiusAttrBoss to the path page item. The corner-size attribute is decoupled from the corner-path implementation, so you could set and change corner size independently and use this setting with other corner implementations. Custom path-end effects You can provide a custom path-end effect with your own path-end implementation through a kPathEndStrokerService. The service provider should provide an implementation of IPathEndStroker. See “Path-end strokers” on page 263. To implement a custom path-end effect, follow these steps: 1. Create a new boss class for the service provider (for example k<XXX>ArrowHeadBoss). Add a service provider to the boss class (the application-provided kPathEndStrokerServiceProviderImpl can be re-used), and define your own implementation of IPathEndStroker. 2. Create your implementation of IPathEndStroker. The interface basically provides drawing and hit testing methods for a stroke end. A page item’s stroke bounding box includes both the stroke and stroke-end bounding box returned from the method on this interface. 3. Set the implementation ID to the appropriate line-end attribute, and apply the attribute to the page item. 290 Graphics Fundamentals Extension patterns Custom page-item adornments Page-item adornments customize the appearance of a page item, giving a plug-in the chance to add drawing when the page item is rendered. For example, if you want to add a drop shadow or label for a specific page item, a page-item adornment is one way to add these extra drawings. Examples of page-item adornments in InDesign are the transparency drop shadow and feather effects, the graphics-frame outline path, and the empty-graphics frame indicator (the X inside the frame). You can participate in page-item drawing by creating a custom page-item adornment. For example, you could provide an adornment to show in magenta type the width and height of each selected page item, as shown in Figure 104. FIGURE 104 Adding adornments to selected page items Before adding adornments After adding adornments Architecture Page-item adornments are represented by boss objects. There are two main types of page-item adornments: z IAdornmentShape implementations, drawn during execution of IShape::Draw. z IAdornmentHandleShape implementations, drawn during execution of IHandleShape::Draw. The Draw methods on their implementations determine the appearance of the adornment. Page-item adornments are connected to page items through the IPageItemAdornmentList interface aggregated on the kPageItemBoss boss class. Figure 105 illustrates the basic data model for adornments. A page item aggregates the IPageItemAdornmentList interface, which stores a list of adornments the page item has. Graphics Fundamentals 291 Graphics Fundamentals Extension patterns FIGURE 105 Adornment data model «boss» kPageItemBoss 1 IPageItemAdornmentList * «boss» kYourAdornmentBoss IPageItemAdornmentList The IPageItemAdornmentList interface manages a list of the adornments for a page item. Each adornment in the list is drawn in an order determined by the value of its AdornmentDrawOrder. For page-item adornments, there are several opportunities within the drawing cycle to draw. Each adornment can be drawn at one or more phases within the drawing cycle if you AND together the flags defined in the AdornmentDrawOrder enumeration (defined in IAdornmentShape.h and IAdornmentHandleShape). These values indicate when the adornment is to be drawn. Upon calling the command kAddPageitemAdornmentCmdBoss, the adornment is inserted into the list based on drawing order. When adding an adornment to a page item, define the adornment as a new boss class that aggregates the IAdornmentShape or IAdornmentHandleShape interface. In a more complex case, you can use more than one adornment for a single page item. IAdornmentShape When implementing IAdornmentShape, you can choose to provide hit testing and invalidation of the view, if needed. At a minimum, your implementation must draw the adornment. When a page item is drawn, each attached adornment is called to draw through the IAdornmentShape interface. A page-item shape tells the drawing manager at which of the following times it should be drawn: z After the frame shape (kAfterShape). z Before the text foreground (kBeforeTextForeground). z At one of the other events defined in the adornment objects. The drawing order controls when the adornment is called to draw. Figure 106 shows the drawing sequences for one rectangle spline item. When the adornments’ drawing methods get called depends on the drawing order. For detailed information on page item drawing, see “Drawing page items” on page 281. 292 Graphics Fundamentals Extension patterns FIGURE 106 Drawing sequences for a rectangle page item DrawMgr Draw kBeforeShape adornments. Set fill path by calling IPathPageItem::CopyPath. Fill shape by calling IPathPageItem::Fill. Draw kAfterFill adornments. Set port’s clip to fill path. Draw children by calling IShape::Draw for each child. Draw kBeforeStroke adornments. Stroke by calling IPathPageItem::Stroke. Draw kAfterStroke adornments. Draw kAfterShape adornments. Continue other drawings. IAdornmentHandleShape Implementing IAdornmentHandleShape lets you decorate the selection handles associated with a page item. This decoration can be drawn with IAdornmentHandleShape::kBeforeShape or IAdornmentHandleShape::kAfterShape; that is, before or after IHandleShape calls DrawHandlesImmediate. Implementation hints To implement a custom page-item adornment, you need to do at least the following: 1. Define an adornment boss class. Depending on the nature of your adornment, you need to implement IAdornmentShape or IAdornmentHandleShape. This determines how and when your adornment is drawn. In providing the implementation aggregated on the adornment boss class, you specify how the adornment is drawn and how the painted bounding box is calculated. 2. Determine when you will connect your adornment to the page-item adornment list, most likely by processing a low-level command. For a sample showing how to implement a custom page-item adornment, see FrameLabel in the SDK; also see other samples that provide an implementation of IAdornmentShape, such as TransparencyEffect and CustomDataLink. Graphics Fundamentals 293 Graphics Fundamentals Extension patterns Custom drawing-event handler You can use a custom drawing-event handler to take control when a page item is being drawn at some point in the drawing cycle, to modify how the item draws or cancel it being drawn. Architecture Drawing events are messages that are broadcast at specific points in the drawing order. Each drawing event signals the beginning or end of a phase of drawing. Drawing events provide extensibility points in that drawing operations can be modified or cancelled in response to the event. Drawing-event types are defined in DocumentContextID.h. Some of the generic drawing event types associated with shape drawing are shown in Table 76. TABLE 76 Generic drawing events Drawing event Use kAbortCheckMessage Opportunity to abort drawing of an entire item. kBeginShapeMessage Start of shape drawing. kDrawShapeMessage Shape drawing is about to begin. kEndShapeMessage End of shape drawing. kFilterCheckMessage Opportunity to filter drawing based on object type. In addition, there are other, more specific event types that signal the beginning and end of spread, layer, and page drawing. Drawing events are generated for each Draw method in the hierarchy: kBegin<XXX>Message, kEnd<XXX>Message, and kDraw<XXX>Message. kBegin<XXX>Message is generated just before a call to the next level of the hierarchy (after any transformation is applied to the object). kEnd<XXX>Message is generated just after execution returns from a lower level of the hierarchy. Registering and unregistering There are two ways a plug-in can register or unregister for drawing events: as a service provider or using direct registration through the IDrwEvtDispatcher interface. 294 z Drawing-event handlers can be a type of service provider. If so, they are automatically registered at start-up. A boss can register as a service provider using the IK2ServiceProvider interface and the kDrawEventService service ID. The boss must provide an implementation of the IDrwEvtHandler interface. When the application starts, the Register method in the drawing-event handler registers for the drawing events it wants to receive. z A second method of registering for events is to instantiate the IDrwEvtDispatcher interface and call IDrwEvtDispatcher::RegisterHandler directly. This requires parameters including the event being registered for, a pointer to the event handler, and the priority of the event handler. Graphics Fundamentals Extension patterns In the PrintSelection SDK sample, the kPrnSelDrawServicesBoss boss class does not provide an implementation for IK2ServiceProvider. This is because this particular sample uses the direct registration method; see the AfterPrintUI method in PrnSelPrintSetupProvider.cpp. Unregistering is similar to registering, except the call to UnRegisterHandler is on the IDrwEvtDispatcher interface. Drawing event-handling priorities Drawing event handlers register their prioritized interest in particular types of drawing events. Priorities are defined in IDrwEvtDispatcher.h. When a handler registers for an event, it must pass a priority to RegisterHandler. The priorities include the following: z kDEHPostProcess z kDEHLowestPriority z kDEHLowPriority z kDEHMediumPriority z kDEHHighPriority z kDEHInitialization As each event is processed, handlers are called in order, from the kDEHInitialization priority down to kDEHPostProcess. If two handlers have the same priority for the same event, the handler registered first is called first. The return code for handlers registered using the kDEHInitialization priority is ignored. For additional information about return codes for the other priorities, see “Handling drawing events” on page 295. Handling drawing events The drawing-event handler’s HandleEvent method takes two parameters: a ClassID that is the eventID (see DocumentContextID.h) and a void pointer to a class containing the event data. For drawing events, this pointer must be cast to the DrawEventData class (see IDrwEvtHandler.h) to access the data. In the HandleEvent method of the drawing-event handler, if the method returns kTrue, it is assumed the event was properly handled and no other event handlers are called for the event; therefore, the drawing at that step ceases. If the method returns kFalse, the drawing event is considered not handled, and the drawing step proceeds. A drawing-event handler that modifies or decorates the drawing of an object but does not replace it returns kFalse. Also, kEnd<XXX>Message does not look at the return code from the event handler, because the draw operation already completed. Implementation A custom drawing-event handler is an extension pattern to let third-party code participate in drawing or printing or interrupt the drawing or printing of a page item. The following steps summarize how to implement a custom drawing-event handler. The signature interface of the pattern is IDrwEvtHandler. Graphics Fundamentals 295 Graphics Fundamentals Swatch-list state 1. Define your own drawing-event handler boss class. 2. Depending on how you want to register and unregister your event handler, you also may need to implement the IK2ServiceProvider interface, returning a ServiceID of kDrawEventService. 3. Provide an implementation of IDrwEvtHandler. 4. In your IDrwEvtHandler::HandleEvent implementation, you will get an event ID and a void pointer to a class containing the event data. You should cast to the DrawEventData and obtain the GraphicsData pointer; then you can do your custom drawing in the same context of page-item drawing. For sample code, see BasicDrwEvtHandler and other samples that implement IDrwEvtHandler in the SDK. Swatch-list state Initial state of swatch list and ink list When the application starts, it initializes a swatch list by creating several default swatches (rendering objects). There are reserved swatches: None, Paper, Black, and Registration. Table 77 lists the initial state of swatch list, and Table 78 illustrates initial ink list. (UIDs are not necessarily the same for different workspaces.) TABLE 77 Initial state of swatches 296 Index UID Rendering object Swatch name Color or gradient information 0 11 kPMColorBoss Black (reserved) kPMCsCalCMYK(0,0,0,1) 1 18 kPMColorBoss C=0 M=0 Y=100 K=0 kPMCsCalCMYK(0,0,1,0) 2 19 kPMColorBoss C=0 M=100 Y=0 K=0 kPMCsCalCMYK(0,1,0,0) 3 20 kPMColorBoss C=100 M=0 Y=0 K=0 kPMCsCalCMYK(1,0,0,0) 4 21 kPMColorBoss C=100 M=90 Y=10 K=0 kPMCsCalCMYK(1,0.9,0.1,0) 5 22 kPMColorBoss C=15 M=100 Y=100 K=0 kPMCsCalCMYK(0.15,1,1,0) 6 23 kPMColorBoss C=75 M=5 Y=100 K=0 kPMCsCalCMYK(0.75,0.05,1,0) 7 12 kPMColorBoss Cyan kPMCsCalCMYK(1,0,0,0) 8 13 kPMColorBoss Magenta kPMCsCalCMYK(0,1,0,0) 9 14 kGraphicStateNoneRenderingO bjectBoss None (reserved) N/A Graphics Fundamentals Swatch-list state Index UID Rendering object Swatch name Color or gradient information 10 15 kPMColorBoss Paper (reserved) kPMCsCalCMYK(0,0,0,0) 11 16 kPMColorBoss Registration (reserved) kPMCsCalCMYK(1,1,1,1) 12 17 kPMColorBoss Yellow kPMCsCalCMYK(0,0,1,0) 13 97 kPMColorBoss (invisible) kPMCsCalCMYK(0,0,0,1) 14 99 kPMColorBoss (invisible) kPMCsCalCMYK(0,0,0,0) 15 98 kGradientRenderingObjectBoss (invisible) Stop 0 UID=99, Stop 1 UID=11 16 100 kAGMBlackBoxRenderingObje ctBoss (invisible) N/A Notice there are several invisible, unnamed swatches that are created but do not show up in the Swatches panel. TABLE 78 Initial ink list Index UID Name Type 0 7 Process Cyan Process 1 8 Process Magenta Process 2 9 Process Yellow Process 3 10 Process Black Process State of swatch list and ink list after adding a custom stop color Adding a custom color swatch, PANTONE 368 C, causes an additional swatch-list entry to be created. For information on how to add a color swatch, see the “Graphics” chapter of Adobe InDesign CS4 Solutions. Table 79 illustrates the new state of the swatch list, and Table 80 illustrates the new state of the ink list. Note the following: z The swatch is sorted by swatch name. Since the new swatch’s name is between index 9 and 10, the new color is inserted into position 10. The following row is added: 10, 167, kPMColorBoss, PANTONE 368 C, kPMCsCalCMYK (0.57,0,1,0), Spot. z The swatch list is reordered, so entries 10 and after are shifted down. The UIDs of the existing swatches do not change. z A new spot ink is added to the ink list. Graphics Fundamentals 297 Graphics Fundamentals Swatch-list state TABLE 79 Swatches after adding a custom color Index UID Rendering object Swatch name Color or gradient information 0 11 kPMColorBoss Black (reserved) kPMCsCalCMYK(0,0,0,1) 1 18 kPMColorBoss C=0 M=0 Y=100 K=0 kPMCsCalCMYK(0,0,1,0) 2 19 kPMColorBoss C=0 M=100 Y=0 K=0 kPMCsCalCMYK(0,1,0,0) 3 20 kPMColorBoss C=100 M=0 Y=0 K=0 kPMCsCalCMYK(1,0,0,0) 4 21 kPMColorBoss C=100 M=90 Y=10 K=0 kPMCsCalCMYK(1,0.9,0.1,0) 5 22 kPMColorBoss C=15 M=100 Y=100 K=0 kPMCsCalCMYK(0.15,1,1,0) 6 23 kPMColorBoss C=75 M=5 Y=100 K=0 kPMCsCalCMYK(0.75,0.05,1,0) 7 12 kPMColorBoss Cyan kPMCsCalCMYK(1,0,0,0) 8 13 kPMColorBoss Magenta kPMCsCalCMYK(0,1,0,0) 9 14 kGraphicStateNoneRendering ObjectBoss None (reserved) N/A 10 167 kPMColorBoss PANTONE 368 C kPMCsCalCMYK(0.57,0,1,0), Spot 11 15 kPMColorBoss Paper (reserved) kPMCsCalCMYK(0,0,0,0) 12 16 kPMColorBoss Registration (reserved) kPMCsCalCMYK(1,1,1,1) 13 17 kPMColorBoss Yellow kPMCsCalCMYK(0,0,1,0) 14 97 kPMColorBoss (invisible) kPMCsCalCMYK(0,0,0,1) 15 99 kPMColorBoss (invisible) kPMCsCalCMYK(0,0,0,0) 16 98 kGradientRenderingObjectBo ss (invisible) Stop 0 UID=99, Stop 1UID=11 17 100 kAGMBlackBoxRenderingObj ectBoss (invisible) N/A TABLE 80 Ink list after a stop color is added to swatch 298 Index UID Name Type 0 7 Process Cyan Process 1 8 Process Magenta Process 2 9 Process Yellow Process 3 10 Process Black Process 4 166 PANTONE 368 C Spot Graphics Fundamentals Swatch-list state Swatch list and ink list after adding a gradient swatch The user also may add a custom gradient. Adding a gradient may add additional colors for a gradient stop. Similar to what occurs when adding a custom color swatch, new entries are created for these added colors and gradients. For information on adding a gradient swatch, see the “Graphics” chapter of Adobe InDesign CS4 Solutions. Table 81 lists only the new entries for the swatch list, and Table 82 illustrates the updated ink list. TABLE 81 New entries in swatch list after adding a custom gradient Index UID Rendering object Swatch name Color or gradient information 13 169 kPMColorBoss Stop 1 kPMCsCalCMYK(0.2,1,0.5,0) 14 171 kPMColorBoss Stop 2 kPMCsCalRGB(0,1,0.5) 15 173 kPMColorBoss Stop 3 kPMCsCalCMYK(0,0.3,0.9,0) 16 174 kGradientRenderingObjectBoss Tie-dye Stop 0 UID=169, Stop 1UID=171, Stop 2 UID =173 The new gradient, Tie-dye, has three stops, so these three color swatches (Stop 1, Stop 2, and Stop 3) also are inserted into the swatch list. For the existing swatches we did not list here, the swatch data did not change, but their indices were changed to make room for new swatches. The new swatches are inserted continuously, because these new swatch names happened to be in continuous position with existing names. TABLE 82 Ink list after a gradient with three-stop colors is added toswatch Index UID Name Type 0 7 Process Cyan Process 1 8 Process Magenta Process 2 9 Process Yellow Process 3 10 Process Black Process 4 166 PANTONE 368 C Spot 5 168 Stop 1 Spot 6 170 Stop 2 Spot 7 172 Stop 3 Spot Since the gradient stop colors are spot colors, they also are added to the ink list. Graphics Fundamentals 299 Graphics Fundamentals Swatch-list state Swatch list and ink list after applying an unnamed color to an object When an instance of a color is chosen with the Color Picker panel and applied to a page item, a new, unnamed swatch entry is added to the end of the swatch list. See Table 83. TABLE 83 New swatch entry added after picking a color from color picker Index UID Rendering object Swatch name Color or gradient information 22 177 kPMColorBoss (invisible) kPMCsCalCMYK(0.4715,0,0.75,0) Unnamed swatches are not sorted, so a new unnamed swatch is appended at the end. After the previous step (adding a gradient), there were 22 swatches total in the list, so this step adds the swatch at index 22. Unnamed swatches do not appear in the Swatches panel, but they can be used for the strokes and fills of document objects by client code. When a color is chosen through the Color panel, the active graphic state changes, and a new swatch may be created. A new swatch is created in the swatch list only if the new color is applied to a document object; i.e., if there is an active selection when the color is created or the color is applied to an object like a spline page item. Because the added unnamed color is a process color, the inks this color uses to print (i.e., Process Cyan, Process Magenta, Process Yellow, and Process Black) already are in the ink list, so the ink list does not change. Applying a new gradient to a page-item object through the Gradient panel results in a similar state. Color spaces There are three common color spaces: RGB, CMYK, and L*a*b*. RGB color spaces RGB is a device-dependent color model. It is the native color model of monitors, scanners and digital cameras. The kPMCsCalRGB space denotes calibrated RGB. Although the space is device-dependent, coordinates within this space are not arbitrary. There are several, slightly different color spaces that use the RGB color model: 300 z Adobe RGB (1998) — Previously referred to as SMPTE-240M. z Apple® RGB — The default color space for Photoshop 3 and 4. z ColorMatch RGB — Based on the Radius PressView display. This has a smaller gamut than Adobe RGB (1998) and other color spaces for print production jobs. z sRGB (IEC61966-2.1) — The default color space for Photoshop 5. This reflects the color properties of the average computer monitor. It was proposed in 1996 by Hewlett-Packard and Microsoft® for representing color on the Internet, as described at http://www.w3.org/Graphics/Color/sRGB.html. sRGB also is the color space used to represent color in SVG documents. For more information about SVG, go to http://www.w3.org/TR/SVG. Graphics Fundamentals Catalog of graphic attributes CMYK Like RGB, CMYK is a device-dependent color model. It is the native color model of most printers. Many color spaces use the CMYK color model. For example, the InDesign color-management user interface lets the end user specify any of the following: z Euroscale Coated v2 z Euroscale Uncoated v2 z Japan Standard v2 z U.S. Sheetfed Coated v2 z U.S. Sheetfed Uncoated v2 z U.S. Web Coated (SWOP) v2 z U.S. Web Uncoated v2 The choice of color space is governed by expectations about the properties of the press on which the job will be printed. LAB L*a*b* (1976 CIE L*a*b* Space) is device-independent and is the basic color model in PostScript. L*a*b* is used for color management as the device-independent model of the ICC device profiles. L*a*b* was standardized in 1976 to provide a space that is perceptually uniform. L*a*b* has its basis in the CIE standard observer, derived by analysis of the physiology of the retina and the early visual pathways. The terms L*, a*, and b* refer to coordinate axes within the space. L is a function of luminance, the physical correlate of brightness. The other coordinates are less easily understood in physical terms and better regarded as mathematical abstractions. Catalog of graphic attributes There are many graphic attributes in the application. Sometimes several attributes collaborate to implement a feature, like transparency; sometimes the values of some attributes are important, like color and stroke-line implementations. Figure 107 is a master list of graphic attributes. The attribute boss class, name, and interface that store the attribute value are listed. Other information is provided in the boolean matrix on the right of the table. The list can be obtained from the API reference documentation in two ways: z Look for IGraphicAttributeInfo and see which boss classes aggregate this interface. z Look at the kGraphicsAttrBoss boss class and examine the list of subclasses of this class. Note this list is not a complete list of graphic attributes and is not updated for each release. Graphics Fundamentals 301 Graphics Fundamentals Catalog of graphic attributes 302 attributeName value interfaces affectsPageItemGeometry? isRequiredGraphicAttribute? isTableAttribute? isTextAttribute? isObservedByGraphicState? isObservedByTransparencyAttrSuite? isFormFieldAttribute? Master list of graphic attributes className FIGURE 107 kCheckDefaultCheckedAttrBoss kCheckExportValueAttrBoss kChoiceAllowMultiSelAttrBoss kChoiceEditableAttrBoss kChoiceListAttrBoss kChoiceSortAttrBoss kDashedAttributeValuesBoss kFormDefaultValueAttrBoss kFormDescriptionAttrBoss kFormExportAttrBoss kFormExportMappingAttrBoss kFormExportRequiredAttrBoss kFormFontColorAttrBoss kFormFontOverprintAttrBoss kFormFontSizeAttrBoss kFormFontStrokeColorAttrBoss kFormFontStrokeOverprintAttrBoss kFormFontStrokeTintAttrBoss kFormFontStrokeWeightAttrBoss kFormFontStyleAttrBoss kFormFontTintAttrBoss kFormFontUIDAttrBoss kFormNameAttrBoss kFormPrintVisibleAttrBoss kFormReadOnlyAttrBoss kFormScreenVisibleAttrBoss kFormSpellCheckAttrBoss kFormStyleAttrBoss kFormTypeAttrBoss kFormValueAttrBoss kGraphicStyleCornerImplAttrBoss kGraphicStyleCornerRadiusAttrBoss kGraphicStyleEvenOddAttrBoss kGraphicStyleFillRenderingAttrBoss Default Is Checked Export Value Allow Multiple Selection Editable Choice List Sort Items Dash settings Form Field Default Value Form Field Description Form Field Export Form Field Export Mapping Name Form Field Required For Export Form Field Font Color Form Field Font Color Overprint Form Field Font Size Form Field Font Stroke Color Form Field Font Stroke Color Overprint Form Field Font Stroke Tint Form Field Font Stroke Weight Form Field Font Style Form Field Font Tint Form Field Font Family Form Field Name Form Field Visible When Printed Form Field Read Only Form Field Visible On Screen Spell Check Form Field Style Form Field Type Form Field Value Effect Size Even-Odd Color IGraphicAttrBoolean IStringAttr IGraphicAttrBoolean IGraphicAttrBoolean IChoiceListAttr (private) IGraphicAttrBoolean IDashedAttributeValues IStringAttr IStringAttr IGraphicAttrBoolean IStringAttr IGraphicAttrBoolean ITextAttrUID IGraphicAttrBoolean IGraphicAttrRealNumber ITextAttrUID IGraphicAttrBoolean IGraphicAttrRealNumber IGraphicAttrRealNumber ITextAttrFont IGraphicAttrRealNumber ITextAttrUID IStringAttr IGraphicAttrBoolean IGraphicAttrBoolean IGraphicAttrBoolean IGraphicAttrBoolean IStringAttr IGraphicAttrInt32 IStringAttr IGraphicAttrClassID IGraphicAttrRealNumber IGraphicAttrBoolean IPersistUIDData no no no no no no no no no no no no no no no no no no no no no no yes no no no no yes yes no yes yes no no no no no no no no yes no no no no no no no no no no no no no no no no no no no no no no no yes yes yes yes no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no yes no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no yes yes yes yes yes yes no yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes no no no no Graphics Fundamentals Graphics Fundamentals affectsPageItemGeometry? isRequiredGraphicAttribute? isTableAttribute? isTextAttribute? isObservedByGraphicState? isObservedByTransparencyAttrSuite? isFormFieldAttribute? kGraphicStyleFillTintAttrBoss Tint kGraphicStyleGapRenderingAttrBoss Gap color kGraphicStyleGapTintAttrBoss Gap tint kGraphicStyleGradientFillAngleAttrBoss Gradient fill angle kGraphicStyleGradientFillGradCenterAttrBoss Gradient fill center kGraphicStyleGradientFillHiliteAngleAttrBoss Gradient fill hilight angle kGraphicStyleGradientFillHiliteLengthAttrBoss Gradient fill hilight length kGraphicStyleGradientFillLengthAttrBoss Gradient fill length kGraphicStyleGradientFillRadiusAttrBoss Gradient fill radius kGraphicStyleGradientStrokeAngleAttrBoss Gradient angle kGraphicStyleGradientStrokeGradCenterAttrBossGradient stroke center kGraphicStyleGradientStrokeHiliteAngleAttrBoss Gradient stroke hilight angle kGraphicStyleGradientStrokeHiliteLengthAttrBossGradient stroke hilight length kGraphicStyleGradientStrokeLengthAttrBoss Gradient stroke length kGraphicStyleGradientStrokeRadiusAttrBoss Gradient stroke radius kGraphicStyleJoinTypeAttrBoss Join kGraphicStyleLineCapAttrBoss End cap kGraphicStyleLineEndEndAttrBoss Line end kGraphicStyleLineEndStartAttrBoss Line start kGraphicStyleMiterLimitAttrBoss Miter limit kGraphicStyleNonPrintAttrBoss Non print kGraphicStyleOverprintFillAttrBoss Overprint fill kGraphicStyleOverprintGapAttrBoss Overprint gap kGraphicStyleOverprintStrokeAttrBoss Overprint stroke kGraphicStyleStrokeAlignmentAttrBoss Stroke alignment kGraphicStyleStrokeLineImplAttrBoss Stroke type kGraphicStyleStrokeRenderingAttrBoss Color kGraphicStyleStrokeTintAttrBoss Tint kGraphicStyleStrokeWeightAttrBoss Stroke weight kStrokeParametersBoss Stroke parameters kTextAlignmentAttrBoss TextAlignment (form field) kTextHasMaxLengthAttrBoss Has Maximum Field Length kTextMaxLengthAttrBoss Maximum Field Length kTextMultilineAttrBoss Multiline IGraphicAttrRealNumber no IPersistUIDData no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrPoint no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrPoint no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrRealNumber no IGraphicAttrInt32 yes IGraphicAttrInt32 yes IGraphicAttrClassID yes IGraphicAttrClassID yes IGraphicAttrRealNumber yes IGraphicAttrBoolean no IGraphicAttrBoolean no IGraphicAttrBoolean no IGraphicAttrBoolean no IGraphicAttrInt32 yes IPersistUIDData IGraphicAttrClassID yes IPersistUIDData no IGraphicAttrRealNumber no IGraphicAttrRealNumber yes IStrokeParameters no IGraphicAttrInt32 no IGraphicAttrBoolean no IGraphicAttrInt32 no IGraphicAttrBoolean no no no no no no no no no no no no no no no no yes yes yes yes yes yes yes no yes no yes yes no yes no no no no no yes yes yes no no no no no no no no no no no no no no no no no no yes no yes no yes yes yes yes no no no no no yes no no yes yes no no yes no yes yes no no yes no no no no no no yes yes no yes no no yes yes yes no no no no no yes yes yes no no no no no no no no no no no no yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no yes yes yes yes value interfaces attributeName className Catalog of graphic attributes 303 Graphics Fundamentals className attributeName value interfaces affectsPageItemGeometry? isRequiredGraphicAttribute? isTableAttribute? isTextAttribute? isObservedByGraphicState? isObservedByTransparencyAttrSuite? isFormFieldAttribute? Catalog of graphic attributes kTextPasswordAttrBoss kTextScrollAttrBoss kTextUseForFileSelAttrBoss kXPBasicBlendModeAttrBoss kXPBasicIsolationGroupAttrBoss kXPBasicKnockoutGroupAttrBoss kXPBasicOpacityAttrBoss kXPDropShadowBlendModeAttrBoss kXPDropShadowBlurRadiusAttrBoss kXPDropShadowColorAttrBoss kXPDropShadowModeAttrBoss kXPDropShadowNoiseAttrBoss kXPDropShadowOffsetXAttrBoss kXPDropShadowOffsetYAttrBoss kXPDropShadowOpacityAttrBoss kXPDropShadowSpreadAttrBoss kXPVignetteCornersAttrBoss kXPVignetteInnerOpacityAttrBoss kXPVignetteModeAttrBoss kXPVignetteNoiseAttrBoss kXPVignetteOuterOpacityAttrBoss kXPVignetteWidthAttrBoss Password Scroll Used For File Selection Mode Isolate blending Knockout group Opacity Mode Blur radius Color Drop shadow Noise X offset Y offset Opacity Spread Corners Inner opacity Feather Noise Outer opacity Feather width IGraphicAttrBoolean IGraphicAttrBoolean IGraphicAttrBoolean IGraphicAttrInt32 IGraphicAttrBoolean IGraphicAttrBoolean IGraphicAttrRealNumber IGraphicAttrInt32 IGraphicAttrRealNumber IPersistUIDData IGraphicAttrInt32 IGraphicAttrRealNumber IGraphicAttrRealNumber IGraphicAttrRealNumber IGraphicAttrRealNumber IGraphicAttrRealNumber IGraphicAttrInt32 IGraphicAttrRealNumber IGraphicAttrInt32 IGraphicAttrRealNumber IGraphicAttrRealNumber IGraphicAttrRealNumber no no no no no no no no no no no no no no no no no no no no no no no no no yes no no yes no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no bo no no no no no no no no no no no no no no no no no no no no no no no no no no no no yes yes yes no no no no no no no no no no no no no no no no no no no no no no yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes yes no no no no no no no no no no no no no no no no no no no Some boss classes inherit from kGraphicsAttrBoss and implement IGraphicAttributeInfo. They are the base classes for graphic attributes, but they do not represent standalone attributes. These bosses are excluded from the master attributes list and are listed in Table 84 for reference. 304 Graphics Fundamentals Catalog of graphic attributes TABLE 84 Parent boss class of attributes Boss ID Description kVignetteAttrBoss Parent attribute boss for all basic feather attributes. kDropShadowAttrBoss Parent attribute boss for all drop-shadow attributes. kXPAttrBoss Parent attribute boss for all basic-transparency attributes. kXPInnerShadowAttrBoss Parent attribute boss for all inner-shadow attributes. kXPOuterGlowAttrBoss Parent attribute boss for all outer-glow attributes. kXPInnerGlowAttrBoss Parent attribute boss for all inner-glow attributes. kXPBevelEmbossAttrBoss Parent attribute boss for all bevel and emboss attributes. kXPSatinAttrBoss Parent attribute boss for all satin attributes. kXPDirectionalFeatherAttrBoss Parent attribute boss for all directional-feather attributes. kXPGradientFeatherAttrBoss Parent attribute boss for all gradient-feather attributes. kDefaultGraphicsAttrBoss Parent of kGraphicStyleNonPrintAttrBoss. kStrokeEffectGraphicsAttrBoss Parent of all stroke-effect attributes (line cap, join type, etc.). kCornerEffectGraphicsAttrBoss Parent of all corner-effect attributes (corner implementation, size). kFillGraphicsAttrBoss Parent of all fill attributes (gradient fill, gradient fill angle, fill color, overprint, etc.). kStrokeGraphicsAttrBoss Parent of all stroke attributes (gradient stroke, gradient-stroke angle, stroke color, stroke weight, etc.). kGradientStrokeGraphicsAttrBoss Gradient stroke itself is parent of all gradientstroke attributes (length, gradient center, radius, etc.). kGradientFillGraphicsAttrBoss Gradient fill stroke itself is parent of all gradient fill attributes (length, gradient center, radius, etc.) Graphics Fundamentals 305 Graphics Fundamentals Mappings between attribute domains Mappings between attribute domains TABLE 85 Graphic-attribute-to-text-attribute mapping Graphic-attribute class Text-attribute class kGraphicStyleFillRenderingAttrBoss kTextAttrColorBoss kGraphicStyleFillTintAttrBoss kTextAttrStrokeTintBoss kGraphicStyleGradientFillAngleAttrBoss kTextAttrGradLengthBoss kGraphicStyleGradientFillGradCenterAttrBoss kTextAttrGradCenterBoss kGraphicStyleGradientStrokeAngleAttrBoss kTextAttrStrokeGradAngleBoss kGraphicStyleGradientStrokeGradCenterAttrBoss kTextAttrStrokeGradCenterBoss kGraphicStyleGradientStrokeLengthAttrBoss kTextAttrStrokeGradLengthBoss kGraphicStyleOverprintFillAttrBoss kTextAttrOverprintBoss kGraphicStyleOverprintStrokeAttrBoss kTextAttrStrokeOverprintBoss kGraphicStyleStrokeRenderingAttrBoss kTextAttrStrokeColorBoss kGraphicStyleStrokeWeightAttrBoss kTextAttrOutlineBoss TABLE 86 Graphic-attribute-to-table-attribute mapping 306 Graphic-attribute class Table-attribute class kGraphicStyleFillRenderingAttrBoss kCellAttrFillColorBoss kGraphicStyleFillTintAttrBoss kCellAttrFillTintBoss kGraphicStyleOverprintFillAttrBoss kCellAttrFillOverprintBoss kGraphicStyleOverprintStrokeAttrBoss kCellStrokeAttrDataBoss kGraphicStyleStrokeLineImplAttrBoss kCellStrokeAttrDataBoss kGraphicStyleStrokeRenderingAttrBoss kCellStrokeAttrDataBoss kGraphicStyleStrokeWeightAttrBoss kCellStrokeAttrDataBoss Graphics Fundamentals Spread-drawing sequence Spread-drawing sequence Once the kLayoutWidgetBoss IControlView implementation obtains a list of the visible spreads, it has to ask each spread to draw through the InDesign draw manager. This section describes the overall sequence for drawing the layout hierarchy. The collaboration for drawing the layout hierarchy is shown in Figure 108. The IControlView implementation on the kLayoutWidgetBoss calls the draw manager once for each visible spread in the window’s view. The draw manager is responsible for creating a GraphicsData object that describes the graphics context for the spread’s drawing. Specifically, it sets the transformation matrix in the graphics port to support drawing in the spread’s parent coordinate system, which is the pasteboard. The draw manager then calls the spread’s IShape::Draw method to initiate the sequence of drawing that spread. Graphics Fundamentals 307 Graphics Fundamentals Spread-drawing sequence FIGURE 108 Boss collaboration for drawing the layout kLayoutWidgetBoss 1. : DrawWithTimedUpdate() IControlView ILayoutControlData kViewPortBoss IDrawMgr 2 : Draw() kSpreadBoss IGeometry IHierarchy IShape 2.1 : Draw() kSpreadLayerBoss IHierarchy IShape kPageBoss 2.1.1 : Draw() IHierarchy IShape kSpreadLayerBoss 2.2 : Draw() IHierarchy IShape kSplineItemBoss 2.2.1 : Draw() IHierarchy IShape kSpreadLayerBoss 2.3 : Draw() IHierarchy IShape kSpreadLayerBoss 2.4 : Draw() IHierarchy IShape kGuideItemBoss 2.4.1 : Draw() IHierarchy IShape When an item’s IShape::Draw method is called, it must draw itself, then its children. This action is analogous to the mechanism used for the IControlView interface on widgets. The IShape implementation provides methods for drawing an object and iterating over the object’s children, asking each of them to draw. Before drawing, the IShape implementation sets the transformation matrix in the graphics port to the item’s inner coordinates. This establishes the following conventions: 308 Graphics Fundamentals Controlling the settings in a graphics port z Each drawing object expects to receive the graphics port set to its parent’s coordinate system. z Each drawing object sets the graphics port to its inner coordinates before drawing itself or calling its children to draw. z Each drawing object reverts the graphics port to its parent’s coordinate system before returning to the caller. Iterating over the object’s children is accomplished by using the IHierarchy interface on each page item. This interface provides methods for iterating over the layout hierarchy. For more information about the IHierarchy interface, see the “Layout Fundamentals” chapter. After being called by the draw manager, spread drawing always follows the layout hierarchy. Users can control whether the guides appear in front of the content or behind it, and this affects the hierarchy. Assuming guides are behind the content, page layers are drawn first, followed by the content layers, then the guide layers. If the guide layers appear in front of the content, the guides draw before the content. All content on a given layer is drawn before proceeding to the next layer. Embedded children of a page item are called to draw before that item completes its drawing. For example, when the kSplineItemBoss is called to draw in step 2.2.1 of Figure 108, if it had children, they would be called to draw as step 2.2.1.1 and 2.2.1.2. before returning to the kSpreadLayerBoss. Controlling the settings in a graphics port The port’s transform can be modified by translations, scale factors, and rotations, and a new transform can be concatenated to the existing port. Concatenation is most often used when page items draw; it is how a page item sets the port to draw to its inner coordinates. Example 22 shows sample code demonstrating this operation. For more information on the application coordinate systems, see the “Layout Fundamentals” chapter. EXAMPLE 22 Manipulating the graphics-port settings // Get the graphics port from gd, a GraphicsData*. IGraphicsPort* gPort = gd->GetGraphicsPort(); if (gPort == nil) return; // Save the current port settings. gPort->gsave(); // Get this page item's ITransform interface. InterfacePtr<ITransform> xform(this, IID_ITRANSFORM); // Concatenate the inner to parent matrix to the port. gPort->concat(xform->CurrentMatrix()); Graphics Fundamentals 309 Graphics Fundamentals Drawing sequence for a page item // Draw a rectangle around the item. InterfacePtr<IGeometry> geo (this, IID_IGEOMETRY); const PMRect r = geo->GetStrokeBoundingBox(); gPort->rectpath(r); gPort->stroke(); // Restore the previous port settings. gPort->grestore(); Drawing sequence for a page item The drawing sequence for a page item that implements IShape involves more than just the drawing instructions. Extensibility points are built into the sequence, in the form of drawing events and adornments. Extensibility points are described in “Extension patterns” on page 289. Although each IShape implementation may have its own specific drawing sequence, all implementations follow these steps as guidelines: 1. When a page item begins drawing, three drawing events are broadcast (kAbortCheckMessage, kFilterCheckMessage, and kDrawShapeMessage). No IShape drawing activities occur between the broadcasts. 2. Save the graphics port state by calling IGraphicsPort::gsave. The graphics port is set to draw in the page item’s inner coordinate system. 3. A kBeginShapeMessage drawing event is broadcast. If any drawing-event handler returns kTrue, the drawing activity ends. 4. Draw kBeforeShape page item adornments. 5. Draw the page item’s own shape by calling the protected method CShape::DrawShape. This method varies depending on the nature of the page item. The following is a list of common tasks the DrawShape method may accomplish: z Define the item’s path. z Fill the path. z Set the port to clip to the path. z Draw the item’s children. z Stroke the path. 6. Draw kAfterShape page-item adornments. There are types of page-item adornments other than kBeforeShape and kAfterShape. These may be called to draw at other points in the sequence. The use of graphics-port save and restore operations allows the adornments and child drawing routines to modify the port as needed and return it to a known state for the next drawing step. 310 Graphics Fundamentals Drawing sequence for a page item For details of the code responsible for drawing, see the CShape.cpp and CGraphicFrameShape.cpp source code in the SDK, under <SDK>/source/public/pageitems/basicinterfaces. For examples of how to create your own shapes, also see the BasicShape and CandleChart sample plug-ins. Graphics Fundamentals 311 Graphics Fundamentals Drawing sequence for a page item 312 Text Fundamentals Concepts Text Fundamentals This chapter provides background on the fundamental concepts used in the text architecture and describes the major subsystems that implement text features. It has the following objectives: z Identify the core subsystems that implement the text architecture. z Describe the model for text content—how raw text and formatting information is managed. z Describe how the presentation of text (i.e., the actual rendered text) is modeled within the application, including both the glyphs that represent the text and the objects that manage the placement of glyphs on a spread. z Describe text composition, the process of taking the content model and incomplete presentation model to generate the final appearance of text in the presentation model. z Describe fonts and how they relate to the InDesign text subsystem. Table 87 lists resources for more information on relevant topics. TABLE 87 For more information For ... Go to ... More information on digital typography topics http://store.adobe.com/type/topics/main.html A glossary of typographic terms http://store.adobe.com/type/topics/glossary.html An overview of Adobe type technology http://partners.adobe.com/asn/developer/type/main.html The PostScript language FAQ list http://www.postscript.org/FAQs/language/FAQ.html Concepts This section introduces the subsystems that implement the text architecture. The core text architecture can be divided into the following core subsystems: text content, text presentation, and text composition. Subsystems that extend the core include import and export, text styles, editors, and text search/replace. See Figure 109. Text Fundamentals 313 Text Fundamentals Concepts FIGURE 109 Overview of core text architecture Visual container Visual container Displays / is displayed by Text layout «uses» Visual container (parcel and text frame) Wax line is created by has Text composition The wax «uses» Content (story thread, character and text attributes) Wax strand Represents composed text has Content The text model Content The text-content subsystem manages the content of a story. The text-content subsystem stores the characters and attributes that control the styled appearance of text. The text-presentation subsystem deals with where the text glyphs appear on the page. Text is composed into frames that display a story. A frame is a visual container for text. Visually, a story is displayed through a linked set of one or more frames. The frames have properties— such as the number of columns, column width, and text inset—that control where text flows. Text-wrap settings on overlapping frames may affect this flow. Once text is composed, it has a visual appearance and exhibits many of the same geometry traits as other page items. The text-composition subsystem manages the process that flows text into a set of specified containers. Fonts provide the text-composition subsystem with the glyph dimensions it needs to arrange glyphs into lines of a given width. 314 Text Fundamentals Text content Text content This section describes how the raw character and formatting information for a story is maintained within the application. Text content represents the information required to render a set of characters. This information includes the Unicode character values, along with any formatting information that defines the look of text, contents of footnotes and tables, inline graphics, and styles that can be applied to text. Stories Text content within a document is represented by a story (signature interface ITextModel). A single, related set of text is maintained within a single story. The document can contain multiple stories. All stories within the document can be accessed through the IStoryList interface on the kDocBoss class. Figure 110 shows this relationship. FIGURE 110 Stories: maintained on the kdocboss, accessed by means of IStoryList. kDocBoss IStoryList 1 IStoryList::GetNthUserAccessibleStoryUID 1..* kTextStoryBoss ITextModel A document can contain private, feature-dependent stories, which are defined not to be useraccessible. Other features (like find/replace and spelling) ignore these stories. Programmatically, they can be accessed through the IStoryList interface, as with any other story. Generally, stories are not directly created or deleted. The life-cycle of a story is controlled as a side effect of another operation. For example, creating a text frame using the Type tool causes a text story to be created, whereas linking two text frames together causes a story to be deleted. It is possible to control the lifetime of a story directly, though the story is still subject to the side effects of manipulating an associated text frame. A story has a length, which can be accessed using ITextModel::TotalLength. A story has a minimum length of one character: a terminating kTextChar_CR, which is inserted into the story when the story is created. This character should not be deleted. Text Fundamentals 315 Text Fundamentals Text content The textual content of a story is maintained independently from the visual containers in which it is contained; i.e., its layout on the page. The text content from a story can be contained within one frame, flow between columns within a frame, or even flow between multiple frames. For example, Figure 111 shows three stories, each flowing through different sets of containers. The model used in maintaining the text content for each is the same. Determining where a particular glyph is rendered is the responsibility of the composer. FIGURE 111 Three text stories flowing through text frames in a spread Information related to the text in a story is maintained by a set of strands. Strands represent parallel sets of information, each of which holds a component of the story. The strands intertwine to give a complete description of the story. Strands are identified using the IStrand signature interface. Some common strands are shown in Figure 112. 316 Text Fundamentals Text content FIGURE 112 The text story aggregates the strands representing the content. kTextStoryBoss ITextModel 1 1 1 1 ITextModel::QueryStrand(kOwnedItemStrandBoss,...) ITextModel::QueryStrand(kTextDataStrandBoss,...) ITextModel::QueryStrand(kCharAttrStrandBoss,...) ITextModel::QueryStrand(kParaAttrStrandBoss,...) 1 kTextDataStrandBoss IStrand Holds Unicode character code data for the text in the story. 1 1 1 kParaAttrStrandBoss IStrand Maintains formatting information applicable to paragraphs. kCharAttrStrandBoss IStrand Maintains formatting information applicable to a range of characters. kOwnedItemStrandBoss IStrand Maintains a link to objects anchored into the text, such as inline images, table frames, and footnotes. Strands Strands (signature interface IStrand) model the linear behavior of text. Each strand represents a different aspect of textual information. A story can be thought of as the composition of the set of strands that contain information for a particular aspect of the story. Figure 112 shows a story with associated text, paragraph-attribute, and character-attribute strands. It also shows the owned item strand used to maintain objects within the text, like inline graphics. Each strand has the same virtual length, equal to the value returned by ITextModel::TotalLength. Each position within a strand refers to the same logical position within the other strands and the story as a whole. For example, position 10 on the kTextDataStrandBoss relates to a particular character—the character at position 10 within the kCharAttrStrandBoss refers to formatting information applicable to this character. Any modification of the text length is reflected in each strand. Figure 113 shows some text and how it might be represented on two strands. While the actual storage mechanism for the strands is of little interest, both strands have the same virtual length. A story (kTextStoryBoss) comprises a set of strands, each with the same length. The figure shows only the data (kTextDataStrandBoss) and paragraph-attribute (kParaAttrStrandBoss) strands. Text Fundamentals 317 Text Fundamentals Text content FIGURE 113 A story and two of its associated strands :kTextStoryBoss ITextModel :kTextDataStrandBoss ITextModel::TotalLength() == 10 :kParaAttrStrandBoss Text storage subsystem I ndex Dat a 0 s 1 o 2 3 m e 4 5 t 6 e 7 x 8 t 9 # I ndex Dat a 0 1 2 3 4 5 6 7 8 9 Format t i ng def i ned by root st yl e Data strand Paragraph attribute strand Strands abstract over the raw data. Developers should not need to interact directly with the storage model below strands. Formatting is defined in “Text formatting” on page 324. Runs Strands are further divided into runs. A run represents something about the content of a particular strand. For the kTextDataStrandBoss, a run is a manageable-sized chunk of text data. For the kParaAttrStrandBoss, a run exists for each paragraph in the story. For the kCharAttrStrandBoss, a run represents a sequence of characters that share the same formatting information. The semantics of a run is defined by its strand. Owned items Owned items (signature interface IOwnedItem) exist to allow some object to be associated with a particular TextIndex position in the text strand. Generally, features anchor the owned item into the text by placing a special character into the kTextDataStrandBoss; however, there is no requirement for associating an owned item with a special character in the data strand. Figure 114 shows an instance diagram associated with a story that contains an inline image. 318 Text Fundamentals Text content The story has the character “a” followed by an inline image, then the character “b.” The owned item strand (kOwnedItemStrandBoss) maintains the UID of the inline object (kInlineBoss). The actual image (kImageItem—note the nonstandard name) is associated through the hierarchy (IHierarchy). FIGURE 114 Instance diagram showing an owned item :kTextStoryBoss IItemStrand::GetOwnedUID for TextIndex 0, 2, and 3 would return kInvalidUID. :kTextDataStrandBoss :kOwnedItemStrandBoss :kInlineBoss IItemStrand 1 IItemStrand::GetOwnedUID(1) IOwnedItem 1 +IHierarchy::QueryChild Text storage subsystem I ndex 0 1 Data a kTextChar_I nline Data Strand IHierarchy 1 2 3 b # I ndex 0 1 2 3 Data UI D for kI nlineBoss # Owned item strand +IHierarchy::QueryParent 0..* :kSplineItemBoss IHierarchy Inline graphic represented by kImageItem 1 +IHiearchy::QueryChild +IHierarchy::QueryParent 0..* :kImageItem IHierarchy Anchored-item positioning The positioning of an inline object relative to its anchor position in the text is controlled through the IAnchoredObjectData interface. The default behavior is defined by the IAnchoredObjectData on the session and document-workspace boss classes. Object styles also can Text Fundamentals 319 Text Fundamentals Text content define how an inline object is positioned (IAnchoredObjectData on kObjectStyleBoss). Specific inline objects can be modified (IAnchoredObjectData on kInlineBoss). The placement of inline objects can be specified as any of the following: z Within the text flow (with variable offset on the y axis). z Above the line, aligned to the center, right, or left of the text or spline. A variable amount of space before and after the inline object can be specified. z A custom position on the page, relative to the anchor point, text frame, page, or spline. As the content that contains the anchor is manipulated (by either adding text that causes the anchor to flow out of the initial frame or manipulating the frames in which the text is contained), the position of the inline object is updated automatically. Story threads Strands model the linear nature of text; however, not all text within a story is linear. For example, an embedded table can have cells with textual content that flows independently from the main text in the story. Story threads (signature interface ITextStoryThread) represent these distinct flows of text. Each story has at least one story thread, the primary story thread, which represents the main text of the story. Other text elements (like footnotes) contained within a story are anchored off the primary story thread using owned items, as described in “Owned items” on page 318. The interface that models story threads (ITextStoryThread) is maintained on the boss class related to the text it represents. For the primary story thread, the interface is found on the kTextStoryBoss. For footnotes, the interface is on kFootnoteReferenceBoss. The story thread maintains text indices that identify the range of text within the story that relates to the particular strands. Figure 115 shows a story with only text within the primary story thread (i.e., the story uses no features requiring other story threads). The story instance (kTextStoryBoss) has four associated strands. There is one story thread (ITextStoryThread) in this story. 320 Text Fundamentals Text content FIGURE 115 Story with only primary story thread :kTextStoryBoss ITextStoryThread::GetTextStart() == 0 ITextStoryThread::GetTextEnd() == 9 ITextStoryThread ITextModel ITextModel::TotalLength() == 10 :kTextDataStrandBoss :kParaAttrStrandBoss :kCharAttrStrandBoss IStrand IStrand IStrand :kOwnedItemStrandBoss IStrand Text storage subsystem I ndex Dat a 0 1 2 3 4 5 6 7 8 9 Format t i ng def i ned by root st yl e I ndex Dat a 0 Paragraph attribute strand I ndex Dat a 0 s 1 o 2 3 m e 4 Data strand 5 t 6 e 7 x 8 t 1 2 3 4 5 6 7 8 No f or mat t i ng def i ned 9 Character attribute strand 9 # I ndex Dat a 0 1 2 3 4 5 6 7 8 9 No i nl i ne obj ect s i n st r eam Owned item strand The primary story thread always begins at TextIndex 0. Other features, like footnotes and tables, use story threads to maintain the feature text as a distinct entity. Figure 116 shows an instance diagram of a story with a footnote. In the figure, a text-story thread (ITextStoryThread) maintains a relationship with some part of the text in a story. In this example, the primary story thread (on kTextStoryBoss) ranges between TextIndex 0 and 3, and the footnote (kFootnoteReferenceBoss) ranges between TextIndex 4 and 8. Text Fundamentals 321 Text Fundamentals Text content FIGURE 116 A story containing a footnote The footnote number and tab are inserted into the footnote automatically. The data strand indicates where the number should be placed using kTextChar_FootnoteMarker. :kTextStoryBoss ITextStoryThread ITextStoryThread::GetTextStart() returns 0 ITextStoryThread::GetTextEnd() returns 3 ITextStoryThread::GetTextSpan() returns 4 :kTextDataStrandBoss :kOwnedItemStrandBoss IItemStrand::GetOwnedUID(1) IItemStrand Text storage subsystem :kFootnoteReferenceBoss I ndex 0 1 2 3 4 5 6 7 8 Data a 0x4 b # 0x4 0x9 y z # ITextStoryThread Data strand I ndex Data 0 1 2 3 4 5 6 7 8 UI D Owned item strand ITextStoryThread::GetTextStart() returns 4 ITextStoryThread::GetTextEnd() returns 8 ITextStoryThread::GetTextSpan() returns 5 0x4 == kTextChar_FootnoteMarker 0x09 == kTextChar_Tab See TextChar.h. Story-thread dictionaries and hierarchies Each distinct instance of a text feature within a story has a distinct text-story thread (ITextStoryThread), including the main story text (the primary story thread). Text-story threads are associated with a particular TextIndex, known as the anchor, obtainable with ITextStoryThreadDict::GetAnchorTextRange. This does not apply to the primary story thread, which is the only thread that always returns an anchor position of zero. An anchor for a footnote appears to the users in the user interface as the footnote-reference character. The anchor for a table appears as the table itself. A text-story thread can contain anchors for other text story threads, subject to some restrictions; for example, footnotes can contain tables but not other footnotes. A feature does not 322 Text Fundamentals Text content need to associate the story thread with a particular TextIndex, in which case it is associated with the end of story marker for the primary text-story thread (these are unanchored threads). A thread block is a contiguous text range (TextRange) that contains the contents for one textstory thread. If a text-story thread contains a set of anchors, the thread blocks associated with these anchors directly follow the thread block for this story thread. This is depicted in Figure 117. Note how the thread blocks for the table directly follows the thread block for the footnote into which it is anchored. In the figure, ITextStoryThreadDict manages the story threads for a particular use of a feature. There is one story thread for the primary story, one for each footnote, and two for the embedded table. FIGURE 117 A story with two footnotes, one containing a two-cell table The auto-numbering characters have been edited out of the footnotes. kTextStoryBoss ITextStoryThreadDict UID3 :kTableModelBoss UID1 : kFootnoteReferenceBoss ITextStoryThreadDict ITextStoryThreadDict QueryStoryThread QueryStoryThread UID2 : kFootnoteReferenceBoss QueryStoryThread QueryStoryThread Text storage subsystem ITextStoryThreadDict I ndex Data Inlines 0 1 2 3 4 5 a 0x4 b 0x4 c # UID1 UID2 Primary story thread Thread block 0 Text Fundamentals 6 7 8 y 0x16 P UID3 9 # 10 11 w # 12 13 x # 14 15 K # Footnote 1 thread Table thread 1 Table thread 2 Footnote 2 thread Thread block 1 Thread block 2 Thread block 3 QueryStoryThread Thread block 4 On data strand: 0x4 == kTextChar_FootnoteMarker 0x16 == kTextChar_Table See TextChar.h. 323 Text Fundamentals Text content The text-story thread dictionary (ITextStoryThreadDict) maintains the set of story threads associated with a particular use of a feature. In Figure 117, each feature has one associated story thread, apart from the table. Each cell in the table has a distinct story thread. ITextStoryThreadDict is responsible for managing the set of threads in the table. Text story threads have a hierarchical relationship (the root being the primary story thread). Individual features are responsible for managing a set of one or more story threads using the story-thread dictionary (ITextStoryThreadDict). In Figure 117, kFootnoteReferenceBoss (UID1) manages one text-story thread, while kTableModelBoss (UID3) manages two story threads, one for each cell. The story maintains a dictionary hierarchy (ITextStoryThreadDictHier), which provides the ability to iterate across all objects that contain a dictionary associated with the story. Text formatting This section describes how the style information that controls the look of text is maintained within the application. Text attributes The fundamental component for formatting text is the text attribute (signature interface IAttrReport). This is a lightweight, non-persistent set of boss objects, each of which describes one text property; for example, the color or point size of text. Attributes are interpreted by the textcomposition subsystem, to define how the text appears when composed. Attributes target either arbitrary ranges of characters (like the color or point size of a set of characters) or a paragraph (like applying a drop cap or setting paragraph alignment). Attributes are managed in an AttributeBossList list, a persistent container class. Consider an AttributeBossList list to be a hash table of attributes, the key being the ClassID. One implication of this is there can be only one instance of any particular attribute within an AttributeBossList list (for example, no conflicting text-color attribute within an AttributeBossList). Attributes can be applied directly (within an AttributeBossList list) to the appropriate paragraph or character-attribute strand, or they can be applied to a text style. An example of applying the attribute directly to the strand would be italicizing text directly using the text editor. Such changes are local to the text being formatted and known as local overrides to the current style. An attribute boss class that supports the IAttrImportExport interface can participate in the import and export of InDesign tagged text files. Default attributes The application provides a set of default attributes. These attributes are maintained within an AttributeBossList on both the session and document workspace. Default attributes define a set of overrides that are applied to any new stories created. These AttributeBossList lists reflect the state of the Character and Paragraph panels when no documents are open (session workspace) or new stories are created (document workspace). When a new document is created, the document workspace inherits the value of the default attributes from the session. The default 324 Text Fundamentals Text content attributes can be updated directly through the Paragraph and Character panels or by selecting styles in the styles panels; the defaults are updated to match the style. Text styles A text style (signature interface IStyleInfo) provides a mechanism to name and persist a particular set of text attributes with particular values. The application supports two kinds of styles for text, paragraph styles and character styles. Each style has an AttributeBossList list that maintains the set of attributes that apply to that style. Access to the attributes in a style is achieved through the ITextAttributes wrapper interface. Character styles are associated with character attributes; however, paragraph styles can be associated with both paragraph and character attributes. Paragraph styles are applied to whole paragraphs; character styles can be applied to arbitrary ranges of text. All text must be associated with both a paragraph style and character style. To support this, the application defines two default styles: the root character style and root paragraph style (known in the application user interface as [No Paragraph Style]). The root paragraph style contains a complete set of paragraph-based and character-based attributes. This defines the default look of text with no further formatting applied. The root character style is empty; it exists purely to provide a root for character styles. Styles form a hierarchy rooted at the root style. Each style (except the root style) is based on a style. The AttributeBossList list for a particular style record only the differences from the style on which it is based; that is, the set of attributes the particular style overrides. This is shown in Figure 118. In the figure, the kStyleBoss for the root paragraph style defines all attributes with a default value. The kStyleBoss for the new style (Yellow Text) contains only the attributes that differ from the root style. The root character style contains no attributes; it exists to provide a root to the character-style hierarchy. Text Fundamentals 325 Text Fundamentals Text content FIGURE 118 Paragraph-style example The application provides two basic styles, for character attributes and paragraph attributes. These are the default styles applied to new stories (assuming no other style is selected in a styles panel). The basic styles cannot be deleted, but you can modify them with plug-ins. Initially, the basic styles are based on the root styles; however, the parent styles can be changed. 326 Text Fundamentals Text content Users can create, edit and delete folders, called Groups, in the Character, Paragraph, and Object Styles palettes. Style group is a collection of styles or groups. The user also can nest groups inside groups and drag styles within the palette to edit the contents of a group. Styles do not need to be inside a group and can exist at the root level of the palette. The group concept also is available in the object style palette. Character and paragraph styles are not required to have unique names across groups; however, sibling styles and groups must have unique names within a parent (i.e., at the same level in the hierarchy). Style names are case-sensitive, so the user can have both “heading” and “Heading” in the same folder. A group and a style cannot have the same name. Since style names are not unique, they are displayed in the user interface as full paths. The alphabetical sort is an action applied to the entire list of styles. Users can rearrange the styles and groups arbitrarily at any time; to view the list alphabetically, they can resort the list with the Sort By Name command. Styles are intermixed with groups for sorting. Sorting is undo-able. The sorting is language specific, based on the user-interface language. Reserved styles like [Basic Paragraph] or [Basic Graphics Frame] are not reordered by this command. Styles are accessible through the style group manager (signature interface IStyleGroupManager) on the document (kDocWorkspaceBoss) and session (kWorkspaceBoss) workspace boss classes. When a document is created, its style group manager inherits the existing set of styles from the session workspace. There are multiple style group managers supported by the workspaces, each identified by a distinct interface identifier; for example, IID_IPARASTYLEGROUPMANAGER and IID_ICHARSTYLEGROUPMANAGER. IStyleGroupManager has one automatically created object of type IStyleGroupHierarchy called “Root Hierarchy,” represented by the kStyleGroupHierarchyBoss. IStyleGroupManager provides access to kStyleGroupHierarchyBoss through its GetRootHierarchy() method. This Root Hierarchy is created on the first call to the GetRootHierarchy method. The kStyleGroupHierarchyBoss holds all the styles (kStyleBoss) and style groups (kStyleGroupBoss) at root level. The key interface on the kStyleGroupHierarchyBoss is IStyleGroupHierarchy, which stores the persistent UID-based style tree hierarchy so you can query information like parent/child node information. All children of this root hierarchy must support the IStyleGroupHierarchy interface; therefore, IStyleGroupHierarchy also is aggregated on the kStyleBoss and kStyleGroupBoss, so access to the style hierarchy also is available if you have access to the UID of any style or style group in the hierarchy. With IStyleGroupHierarchy, you gain access to the style-tree hierarchy the user sees in the style panel. IStyleGroupHierarchy has a method to traverse the style hierarchy, which should be used to iterate through all styles. IStyleGroupManager also provides two overloaded FindByName() methods that return the UID of a style or style group. Figure 119 shows how to navigate the styles, given a particular workspace. The style group manager (IStyleGroupManager on document and session workspaces) provides access to all paragraph and character styles (kStyleBoss) through the GetRootHierarchy() method, which returns an IStyleGroupHierarchy on the kStyleGroupHierarchyBoss. kStyleGroupHierarchyBoss holds all the styles (kStyleBoss) and style groups (kStyleGroupBoss) at root level. Styles can be iterated over using IStyleGroupHierarchy::GetDescendents or accessed by name using IStyleGroupManager::FindByName. Given a particular style, the style it is based on can be accessed using IStyleInfo::GetBasedOn. Text Fundamentals 327 Text Fundamentals Text content FIGURE 119 Navigating styles in a document «boss» kDocWorkspaceBoss 1 The IStyleGroupManager is the access point for style set management. It gives access to the root IStyleGroupHierarchy from where you can get the full style set hierarchy +IStyleGroupManager IStyleGroupManager::GetRootStyleUID 1 IStyleGroupManager::GetRootHierarchy 1 IStyleGroupHierarchy is aggregated on kStyleGroupHierarchyBoss, kStyleBoss, and kStyleGroupBoss, it is used to access kStyleBoss/kStyleGroupBoss current object may have. +IStyleGroupHierarchy IStyleGroupHierarchy::QueryChild 1 1 0..* «boss» kStyleBoss 0..1 Holds all the styles (kStyleBoss) and style groups (kStyleGroupBoss) at root level. «boss» kStyleGroupHierarchyBoss +IStyleGroupHierarchy +IStyleInfo IStyleGroupHierarchy can be used to access its styles and groups. 1 0..* IStyleGroupHierarchy::QueryChild 0..* «boss» kStyleGroupBoss +IStyleGroupHierarchy IStyleGroupHierarchy::QueryChild IStyleInfo::GetBasedOn 1 Represents a text style 1 1 0..* IStyleGroupHierarchy::QueryChild Represents a style group Sorting the style hierarchy is done through the IStyleGroupHierarchy::Sort() method, when it is invoked, it sorts its children and calls its children’s Sort method. The call to Sort() on the root hierarchy recursively sorts all styles. This methods takes a flag to indicate whether to sort in descending/ascending order, all child or immediate child, etc. Text formatting and stories All text has an associated character- and paragraph-attribute style. This style is either the root style (which defines a default value for the complete set of attributes used in composition) or a style that records differences from the root style. Styles form a hierarchy in which the values of attributes in child nodes override those in parent nodes. As well as having the character and paragraph styles defined on the attribute strands, local overrides can be applied. This occurs when a formatting change is made without modifying a style; for example, selecting a word and making it bold. 328 Text Fundamentals Text content Attributes describe one of the text’s appearance and are used by the composition engine when rendering the associated glyphs. IComposeScanner (on the kTextStoryBoss) provides APIs that allow the value of any attribute to be deduced for any TextIndex. Figure 120 shows an example of how styles and local attribute overrides combine to describe the exact look of text. The paragraph-attribute strand specifies the text will use the custom style pStyle and two local overrides. The overrides specify the body and last line of the paragraph are to be centered. The character-attribute strand specifies the root style for the word “Aliens,” a local +bold override for the word “and,” and the word “Earth” to use the custom style cStyle. FIGURE 120 Formatting and strands Story length = 17 0 kTextDataStrandBoss 1 A l 2 3 4 5 i e n s kParaAttrStrandBoss 6 7 8 9 10 a n d Start: 0 End: 16 UID: pStyle 11 12 13 14 15 16 E a r t h # Overrides: + last: centered + body: centered kCharAttrStrandBoss Start: 0 End: 6 UID: root Start: 7 End: 9 UID: root Start: 10 End: 16 UID: cStyle Overrides: None Overrides: +bold Overrides: None kTextAttrFontStyleBoss +bold kStyleBoss name: root based on: none AttributeBossList always empty kStyleBoss name: cStyle kTextAttrAlignBodyBoss kTextAttrAlignLastBoss + body: centered + last: centered based on: root AttributeBossList kTextAttrUnderlineBoss +underline kStyleBoss name: root based on: none AttributeBossList all attributes described here kTextAttrPointSizeBoss kStyleBoss name: pStyle based on: root AttributeBossList +size: 24 pt Text Fundamentals 329 Text Fundamentals Text content Class associations Figure 121 shows the major classes and associations for text content. FIGURE 121 Major classes and associations for text content «interface» kDocBoss kTextStoryBoss IStoryList GetNthTextModelUID + GetNthTextModelUID() : UIDRef «interface» ITextModel + QueryStrand(PMIID, ClassID) : IPMUnknown * QueryStrand QueryStrand kTextDataStrandBoss QueryStrand kParaAttrStrandBoss kCharAttrStrandBoss IStrand IStrand QueryStrand kOwnedItemStrandBoss IStrand IStrand ITextStrand «interface» «interface» IAttributeStrand IItemStrand + GetStyleUID() : UID + GetNthOwnedUID() : UID GetStyleUID kStyleBoss Other owned item boss kStyleBoss kTableFrameBoss kStyleBoss kStyleBoss 330 GetNthOwnedUID kFootnoteReferenceBoss kInlineBoss Text Fundamentals Text presentation Text presentation This section describes the presentation model responsible for managing the final look of text. The layout factors (such as the types of containers with which text can be associated) are described before the representation of the rendered text (the wax) is presented. The text-presentation model represents both the information required to place a set of glyphs on a spread and the management of those glyphs within the application. In Figure 109, this is represented by the text layout and wax components. Text layout is concerned with the containers for text and the attributes of a container that can affect how text is placed in respect to that container. The wax models the actual glyphs rendered into the layout. Text layout Text layout defines the shape and form of the visual containers in which text is composed and displayed. The textual content is maintained in the text model of the story associated with the layout. This content is divided into one or more story threads, each representing an independent flow of text. See “Story threads” on page 320. In text composition, text flows from the story thread into its associated visual containers to create wax that fits the layout. Text layout, in turn, displays the wax. When the layout is updated, text is recomposed to reflect the change. Text frame The text frame is the fundamental container used to place and display text. Text frames have properties, like the number of columns, column width, gutter width, and text inset, that control where text flows. A text frame is represented by several associated boss classes. Figure 122 shows a text frame containing two columns, with one line of text displayed in each column. Figure 123 shows how this instance of a text frame is represented internally. FIGURE 122 Text frame TEXTFRAME -POINTINSET -POINTGUTTER OUTPORT INPORT COLUMN Text Fundamentals COLUMN 331 Text Fundamentals Text presentation FIGURE 123 Instance diagram of text frame Text frame «boss class» graphic frame : layout::kSplineItemBoss UID = 176 IHierarchy::QueryParent IHierarchy::QueryChild(0) IHierarchy::QueryParent «boss class» controller : kMultiColumnItemBoss UID = 177 IHierarchy::QueryChild(0) «boss class» column 1 : kFrameItemBoss UID = 179 IHierarchy::QueryParent IHierarchy::QueryChild(1) «boss class» column 2 : kFrameItemBoss UID = 180 As shown in Figure 124, a text frame consists of a graphic frame (kSplineItemBoss) containing one multicolumn item (kMultiColumnItemBoss). The multicolumn item (kMultiColumnItemBoss) is the controller for the text frame and contains one or more columns (kFrameItemBoss). The ITextColumnSizer interface stores the major properties of the text frame, such as the number of columns. IMultiColumnTextFrame provides access to the associated story, frame list, and the range of text displayed. 332 Text Fundamentals Text presentation FIGURE 124 Structure of a text frame Text frame Represents the graphic frame Represents the controller for the text frame «boss class» layout::kSplineItemBoss 1 IHierarchy::QueryParent 1 IHierarchy::QueryChild «boss class» kMultiColumnItemBoss 1 1..* Represents a column within the text frame IGraphicFrameData ITextColumnSizer The relationship between the graphic frame and its content is maintained by the IHierarchy interface. IMultiColumnTextFrame IHierarchy::QueryParent IHierarchy::QueryChild «boss class» kFrameItemBoss IGraphicFrameData::GetTextContentUID is a helper method that returns the UID of the associated kMultiColumnItemBoss or kInvalidUID if the frame does not have textual content. Stores the major properties of a text frame, such as the number of columns Provides access to the associated story, frame list, and the range of text displayed ITextFrameColumn The relationship between the graphic frame (kSplineItemBoss) and its content is maintained by the IHierarchy interface. Use IHierarchy::QueryChild to navigate from the graphic frame to its associated multicolumn item, then onto individual columns. Conversely, use IHierarchy::QueryParent to navigate up from a column to the multicolumn item and on up to the graphic frame. Frame list A story (kTextStoryBoss) associates the text frames that display its content through the frame list (kFrameListBoss). Conversely, a text frame associates the story whose text it displays through the frame list. Figure 125 and Figure 126shows the story and frame list objects for the example introduced in Figure 122 and Figure 123. Figure 127 shows the general structure of the frame list (IFrameList) for a story. FIGURE 125 Text Fundamentals Frame list 333 Text Fundamentals Text presentation FIGURE 126 Instance diagram of frame list Text frame «boss class» graphic frame : layout::kSplineItemBoss UID = 176 IHierarchy::QueryParent IHierarchy::QueryChild(0) IHierarchy::QueryParent «boss class» controller : kMultiColumnItemBoss UID = 177 IHierarchy::QueryParent IHierarchy::QueryChild(1) IHierarchy::QueryChild(0) «boss class» column 2 : kFrameItemBoss UID = 180 «boss class» column 1 : kFrameItemBoss UID = 179 IFrameList::QueryNthFrame(1) IFrameList::QueryNthFrame(0) «boss class» frame list : kFrameListBoss ITextFrameColumn::QueryFrameList UID = 174 ITextFrameColumn::QueryFrameList ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» story : The Text Model::kTextStoryBoss UID = 158 334 Text Fundamentals Text presentation FIGURE 127 Structure of the frame list (IFrameList) for a story Text frame «boss class» layout::kSplineItemBoss IGraphicFrameData 1 IHierarchy 1 «boss class» kMultiColumnItemBoss IMultiColumnTextFrame 1 IHierarchy 1..* «boss class» kFrameItemBoss 1..* ITextFrameColumn IFrameList::QueryNthFrame ITextFrameColumn::QueryFrameList 1 IMultiColumnTextFrame::QueryFrameList «boss class» kFrameListBoss Associates the story and the frames that display its text Represents text content IFrameList 1 ITextModel::QueryFrameList 1 IFrameList::QueryTextModel «boss class» The Text Model::kTextStoryBoss ITextModel ITextFrameColumn::QueryTextModel Provides access to the story's text content IMultiColumnTextFrame::QueryTextModel Text Fundamentals 335 Text Fundamentals Text presentation Threading and text frames The text in a frame can be independent of other frames, or it can flow between threaded frames. Threading of text is the process of connecting the flow of text between frames. Do not confuse threading text between frames with text-story threads. The connections can be visualized by selecting a text frame and choosing View > Show Text Threads, as shown in Figure 130. Threaded frames share a common underlying story (kTextStoryBoss) and can be on the same spread or different spreads in the same document. Figure 128 shows two unthreaded text frames. Because each text frame is associated with a distinct story, editing the text in one of the frames does not affect the text in the other frame (see Figure 129). FIGURE 128 Unthreaded text frames INPORTATBEGINNINGOFSTORY OUTPORTINDICATINGOVERSETTEXT 4WO-COLUMNFRAME /NE-COLUMNFRAME INPORTATBEGINNINGOFSTORY 336 OUTPORTATENDOFSTORY Text Fundamentals Text presentation FIGURE 129 Instance diagram of unthreaded text frames Two-column text frame One-column text frame «boss class» graphic frame 1 : layout::kSplineItemBoss UID = 176 «boss class» graphic frame 2 : layout::kSplineItemBoss UID = 262 IHierarchy IHierarchy «boss class» controller : kMultiColumnItemBoss UID = 177 «boss class» controller : kMultiColumnItemBoss UID = 264 IHierarchy IHierarchy IHierarchy «boss class» column 1 : kFrameItemBoss UID = 179 «boss class» column 2 : kFrameItemBoss UID = 180 «boss class» column 1 : kFrameItemBoss UID = 281 IFrameList::QueryNthFrame(0) IFrameList::QueryNthFrame(1) -IFrameList::QueryNthFrame(0) ITextFrameColumn::QueryFrameList ITextFrameColumn::QueryFrameList -ITextFrameColumn::QueryFrameList «boss class» frame list : kFrameListBoss UID = 174 ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» story 1 : The Text Model::kTextStoryBoss UID = 158 «boss class» frame list : kFrameListBoss UID = 335 -ITextModel::QueryFrameList -IFrameList::QueryTextModel «boss class» story 2 : The Text Model::kTextStoryBoss UID = 319 When the text frames that display a story cannot display all the text, the unseen text is called “overset text.” A red plus sign (+) on the outport of the two-column frame indicates the story has overset text. If the user clicks the outport of the two-column frame with the Selection tool and then clicks the inport of the one-column frame, the frames become threaded. In Figure 130, the text from the two-column frame that was overset now flows through the one-column frame. During this process, the text from the story underlying the one-column frame is appended to the story underlying the two-column frame. The frame list (kFrameListBoss) and story (kTextStoryBoss) underlying the one-column frame are deleted. Once threaded, the two frames share the same underlying story (see Figure 131). Text Fundamentals 337 Text Fundamentals Text presentation FIGURE 130 Threaded text frames INPORTATBEGINNINGOFSTORY OUTPORTINDICATINGLINKTONEXTFRAME 4WO-COLUMNFRAME /NE-COLUMNFRAME INPORTINDICATINGLINKFROMPREVIOUSFRAME FIGURE 131 Instance diagram of threaded text frames Two-column text frame One-column text frame «boss class» graphic frame 1 : layout::kSplineItemBoss UID = 176 «boss class» graphic frame 2 : layout::kSplineItemBoss UID = 262 IHierarchy IHierarchy «boss class» controller : kMultiColumnItemBoss UID = 177 «boss class» controller : kMultiColumnItemBoss UID = 264 IHierarchy IHierarchy IHierarchy «boss class» column 1 : kFrameItemBoss UID = 179 «boss class» column 2 : kFrameItemBoss UID = 180 «boss class» column 1 : kFrameItemBoss UID = 281 IFrameList::QueryNthFrame(0) IFrameList::QueryNthFrame(1) ITextFrameColumn::QueryFrameList ITextFrameColumn::QueryFrameList «boss class» frame list : kFrameListBoss UID = 174 ITextFrameColumn::QueryFrameList ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» story 1 : The Text Model::kTextStoryBoss UID = 158 338 OUTPORTINDICATINGOVERSETTEXT IFrameList::QueryNthFrame(2) Text Fundamentals Text presentation Parcels A flow of text content within a story is a story thread, is represented by a boss class with an ITextStoryThread interface. A parcel is a visual container into which the text of a story thread is flowed for layout and display. A parcel is represented by a boss class with an IParcel interface. The text of a story thread (ITextStoryThread) can be composed into a list of parcels (IParcel) in a parcel list (IParcelList). Examples of application-provided parcels are as follows: z Text frame item (kFrameItemBoss) z Table cell parcel (kTextCellParcelBoss) z Footnote parcel (kFootnoteParcelBoss) Figure 132 shows how text frames support story threads and parcels. The text in the primary story thread is displayed through parcels given by the parcel list on the frame list. These parcels are the frame items of the text frames that display the story. Text Fundamentals 339 Text Fundamentals Text presentation FIGURE 132 Structure of the parcel implementation for text frames Text frame «boss class» layout::kSplineItemBoss 1 1 «boss class» kMultiColumnItemBoss 1 Displays a range of text from the primary story thread 1..* IParcel «boss class» kFrameItemBoss 1..* IParcelList::QueryParcel The range of text displayed in the parcels can be found in ITextParcelList. 1 IParcel::QueryParcelList ITextParcelList IParcelList «boss class» kFrameListBoss 1 ITextStoryThread::QueryParcelList Text in the primary story thread flows into parcels in this parcel list. Effectively, this flows the content through the text frames. 1 ITextParcelList::QueryStoryThread «boss class» The Text Model::kTextStoryBoss ITextStoryThread ITextStoryThreadDict ITextModel The primary story thread 340 Text Fundamentals Text presentation Figure 133 shows how tables support story threads and parcels. The text for the story thread of a table cell (kTextCellContentBoss) is displayed through the parcels given by its parcel list. These parcels are text cell parcels (kTextCellParcelBoss). For more information, see the “Tables” chapter. FIGURE 133 Structure of the parcel implementation for tables Text frame A table frame (kTableFrameBoss) represents the rows of a table that lie in a frame item (kFrameItemBoss). The rows of a table can flow across one or more frame items (kFrameItemBoss). «boss class» layout::kSplineItemBoss 1 1 0..* 1 «boss class» kMultiColumnItemBoss «boss class» table::kTableFrameBoss ITableLayout::frame_iterator::QueryFrame 1 Displays a range of text from the cell's story thread 1 1 ITableFrame::QueryFrame 1..* 1..* IParcel «boss class» kFrameItemBoss 1..* IParcel::GetFrameUID IParcelList::QueryParcel IParcel::QueryParcelList «boss class» kFrameListBoss 1 ITableFrame::const_parcel_iterator «boss class» table::kTextCellParcelBoss 1..* Each text cell in a table knows the frame item (kFrameItemBoss) in which it lies; unless it is overset, in which case the cell is not displayed. 1 ITableFrame IOwnedItem IWaxAnchorPt ITextParcelList IParcelList ITextStoryThread::QueryParcelList IParcel IParcelList::QueryParcel The range of text displayed in the parcels can be found in ITextParcelList. 1 IParcel::QueryParcelList «boss class» table::kTextCellContentBoss 1..* ITextParcelList IParcelList ITextStoryThread ITextStoryThreadDict::QueryThread Each cell has a story thread whose text flows into parcels in the cell's parcel list. 1 1 ITableFrame::QueryModel ITextParcelList::QueryStoryThread «boss class» The Text Model::kTextStoryBoss 1 ITextStoryThread::GetDictUID «boss class» table::kTableModelBoss 1 ITextStoryThread ITextStoryThreadDict ITextModel lTableModelList::QueryNthModel ITextStoryThreadDict ITableTextContainer ITableModel 0..* ITableTextContainer::QueryTextModel A table model exists for each table embedded in the story. Text Fundamentals 341 Text Fundamentals Text presentation Span Each object that displays text is associated with a story thread. After composition, the object stores the index (TextIndex) into the text model of the first character it displays and the total number of characters it shows. This text range is the span. The span is available on several interfaces (see Table 88 and Table 89). Table 88 lists the APIs that indicate the range of text displayed. Table 89 lists the APIs that find the parcel or frame displaying a specific TextIndex. The ranges returned from these APIs are accurate only if the text in the object is fully composed. Before relying on these methods, you must check for damage and for the object to recompose, if necessary. TABLE 88 APIs that indicate the range of text displayed NOTE: API Description IFrameList Gives the range of text displayed by each frame item (kFrameItemBoss). ITextFrameColumn Gives the range of text displayed by the frame item (kFrameItemBoss). IMultiColumnTextFrame Gives the range of text displayed by the multicolumn item (kMultiColumnItemBoss). ITextParcelList Gives the range of text displayed by a parcel. All objects that display composed text are a kind of parcel (IParcel). TABLE 89 APIs that find the parcel or frame displaying a specific TextIndex API Description IFrameList::QueryFrameContaining Use this method to find the frame item (kFrameItemBoss) that displays the character at a specific index (TextIndex) in the text model. ITextModel::QueryTextParcelList Call this to find the text parcel list associated with a given TextIndex. After you have the ITextParcelList, use ITextParcelList::GetParcelContaining, then IParcelList::QueryParcel. All objects that display composed text are a kind of parcel (IParcel). As a result, this approach finds parcels for text frames, table cells, or other new kinds of parcels. Note, however, that some text embedded in the text model may not be composed or displayed in a parcel. IWaxIterator After you know the text model (ITextModel) and the range of text you want, use this class to get the wax data. TextIterator After you know the text model (ITextModel) and the range of text that you want, use this class to get the character data. Figure 134 shows a story displayed in a two-column frame. The range of text displayed in both columns is available in the IMultiColumnTextFrame interface on the multicolumn item (kMultiColumnItemBoss). The range of text available in each frame item (kFrameItemBoss) is available in both ITextFrameColumn and ITextParcelList. 342 Text Fundamentals Text presentation FIGURE 134 Finding the range of text displayed in a frame or parcel K-ULTI#OLUMN)TEM"OSS 3TART3PAN K&RAME)TEM"OSS 3TART3PAN K4EXT3TORY"OSS )4EXT-ODEL K&RAME)TEM"OSS 3TART3PAN 4HETEXTCONTENTISSTOREDin THEASSOCIATED STORYgSTEXTMODEL$ETERMINETHERANGE YOUWANT, andTHENUSETHE4EXT)TERATOR class TOACCESSTHECHARACTERDATA 4EXT)NDEX #HARACTER!LIENSAND%ARTHr Conversely, you can discover the parcel (IParcel) displaying the character at a specific index (TextIndex) in the text model. It is possible the TextIndex of interest is overset text that is not displayed. The kind of parcel returned depends on the kind of story thread (ITextStoryThread) that owns the range of text in which the TextIndex lies. For example, if the TextIndex lies in the primary story thread, it is in the range 0 to (ITextModel::GetPrimaryStoryThreadSpan - 1). The primary story thread is displayed by the text frames associated with the story. In this case, the frame item (kFrameItemBoss) that displays the desired TextIndex is determined. Alternately, the desired TextIndex can be in the range ITextModel::GetPrimaryStoryThreadSpan to (ITextModel::TotalLength - 1). Text in this range is associated with a table or other feature that embeds text in stories, like notes, footnotes, or tracked changes. If the feature displays composed text, the parcel displaying a specific TextIndex can be determined. Text frames and the wax After text is composed, each line is represented by a wax line (kWaxLineBoss). The wax for a story is owned by the wax strand. A text frame is associated with its wax lines by the range of text displayed, which is obtained from ITextFrameColumn or ITextParcelList. The range of text displayed by the frame is maintained when text is recomposed. Wax lines are accessed using a wax iterator, IWaxIterator, which is a C++ helper class created by calling IWaxStrand::NewWaxIterator. Consider the wax for a text frame with two columns, each displaying one line of text. See Figure 135. Here, the wax line (kWaxLineBoss) objects do not have UIDs. They are managed by the wax strand (IWaxStrand on kFrameListBoss) that persists some wax data and regenerates the rest by recomposing the text when required. Text Fundamentals 343 Text Fundamentals Text presentation FIGURE 135 Structure of the wax for a text frame Text frame The wax associated with a text frame can be discovered by using a wax iterator (IWaxIterator) to find the wax lines (IWaxLine) for the the range of text displayed by the frame (see ITextFrameColumn). «boss class» layout::kSplineItemBoss IWaxStrand::NewWaxIterator is called to create an IWaxIterator. IWaxIterator is a helper class that can access the wax lines associated with a given TextIndex. 1 IHierarchy::QueryParent 1 IHierarchy::QueryChild «boss class» kMultiColumnItemBoss IWaxIterator is not a descendant of IPMUnknown. It should not be used in conjunction with InterfacePtr. 1 1..* IHierarchy::QueryParent IHierarchy::QueryChild 0..1 0..* IWaxIterator::GetFirstWaxLine «boss class» The Wax::kWaxLineBoss «boss class» kFrameItemBoss IWaxLine::GetParcelKey 1..* IWaxLine ITextFrameColumn IFrameList::QueryNthFrame ITextFrameColumn::QueryFrameList 1 IWaxIterator::GetFirstWaxLine 0..* 1 IWaxLine::QueryWaxStrand The wax lines associated with a story can be found by using a wax iterator (IWaxIterator) for the range of text of interest. A wax line for text in the range 0..(ITextModel::GetPrimaryStoryThreadSpan-1) will be associated with a frame item (kFrameItemBoss), unless the wax line represents overset text (in which case it is not displayed). A wax line for text in the range ITextModel::GetPrimaryStoryThreadSpan.. (ITextModel::TotalLength-1) may be associated with other kinds of parcel, such as table text cells (kTextCellParcelBoss). This is not shown on the diagram. 344 «boss class» kFrameListBoss IWaxStrand IFrameList 1 ITextModel::QueryFrameList 1 IFrameList::QueryTextModel Manages the wax for a story «boss class» The Text Model::kTextStoryBoss Text Fundamentals Text presentation Text-frame options You manipulate text-frame options from the dialog box invoked by choosing Object > Text Frame Options. Default text-frame options store the properties inherited when a new text frame is created. The text-frame options are stored in the ITextOptions interface on the document workspace. A distinct set of defaults are maintained on the session workspace and are inherited. Figure 136 and Figure 137 show the boss classes and interfaces involved. FIGURE 136 Interfaces storing text-frame options on a text frame yPosition Tile for line 1 Baseline -15 -5 FIGURE 137 Interfaces storing default text-frame options Document-specific defaults that are inherited by new text frames Session-specific defaults that are inherited by new documents IWorkspace «boss class» kDocWorkspaceBoss ITextOptions ITextOptions IWorkspace «boss class» kWorkspaceBoss Text-frame geometry In Figure 138, the bounds of the page items that make up the text frame are tabulated in the inner coordinates of the spline. In Table 90, the geometries of the multicolumn and column items are expressed in the coordinate space of their parent, the spline. Effectively, they share a common coordinate space. FIGURE 138 Text-frame geometry -100,-15 0,0 100,15 Text Fundamentals 345 Text Fundamentals Text presentation TABLE 90 Text-frame geometry Item Left Top Right Bottom kFrameItemBoss (left column) -100.00 -15.00 -5.00 15.00 kFrameItemBoss (right column) 5.00 -15.00 100.00 15.00 kMultiColumnItemBoss -100.00 -15.00 100.00 15.00 kSplineItemBoss -100.00 -15.00 100.00 15.00 Text Inset Text inset, a property of a text frame, is an area between the edge of the frame and the area where text flows. If the text frame is regular in shape, you can specify the inset independently for each side (see Figure 139). With irregularly shaped frames, the inset follows the contour of the text frame, and there is only one inset value (see Figure 140). FIGURE 139 Text Inset TOPINSET POINTS LEFTINSET POINTS RIGHTINSET POINTS BOTTOMINSET POINTS FIGURE 140 Irregular text inset INSET POINTS 346 Text Fundamentals Text presentation Figure 141 shows the structure of a text inset. The properties of the text inset are found in the ITextInset interface on the text frame’s kSplineItemBoss. Even when there is no text inset in effect (all insets have a value of 0 points), a kTextInsetPageItemBoss is associated with the text frame and describes the contour of the text inset. FIGURE 141 Structure of text inset Text frame 1 «boss class» layout::kSplineItemBoss 1 ITextInset::QueryInsetGeometry ITextInset 1 «boss class» kTextInsetPageItemBoss IStandOffItemData::QueryPageItem 1 «boss class» kMultiColumnItemBoss «boss class» kFrameItemBoss Text inset is a special kind of standoff, which is the abstraction that represents text wrap. IStandOffItemData IPathGeometry Represents the contour of the inset associated with the text frame «boss class» kStandOffPageItemBoss Text wrap Text in a text frame is affected by other page items that have text wrap applied. Text wrap is represented by a standoff abstraction. A standoff describes whether there should be text wrap and, if so, the contour around which the text should be wrapped. Figure 142 shows an empty graphic frame with text wrap set at a 4-point offset around the frame’s path. Figure 143 shows that if there is no intersection between the boundary of the standoff and the boundary of the text frame, then the text in the text frame is not affected. FIGURE 142 MODE Form Text-wrap properties applied to empty frame EMPTYGRAPHICFRAME K3PLINE)TEM"OSS 4HEMODEMARGIN,ANDFORMPROPERTIES ARESTOREDININTERFACE)3TAND/FF$ATA. MARGIN Text Fundamentals STANDOFF K3TAND/FF0AGE)TEM"OSS 347 Text Fundamentals Text presentation FIGURE 143 Text wrap: empty frame with text wrap alongside text frame Figure 144 shows what happens when the empty graphic frame overlaps the text frame. The text within that frame is forced to wrap around the empty frame, which is said to repel the text. By inverting the text wrap, a page item can indicate it is to be used to attract text within its boundary rather than repel it. Figure 145 shows how this causes text to flow within the set boundaries. FIGURE 144 Text wrap: empty frame with text wrap overlapping text frame FIGURE 145 Text wrap: empty frame with inverted text wrap overlapping text frame The objects representing the text wrap for the sample are shown in Figure 146. The general structure of text wrap is shown in Figure 147. 348 Text Fundamentals Text presentation FIGURE 146 Instance diagram for text wrap IStandOffData::QueryStandOffGeometry «boss class» empty graphic frame : layout::kSplineItemBoss UID = 200 Text frame «boss class» graphic frame : layout::kSplineItemBoss UID = 176 «boss class» stand off : kStandOffPageItemBoss UID = 201 «boss class» controller : kMultiColumnItemBoss UID = 177 IStandOffItemData::QueryPageItem «boss class» column 1 : kFrameItemBoss UID = 179 Empty graphic frame with standoff to represent the text wrap FIGURE 147 Structure of text wrap Text wrap is represented by a standoff. A standoff can be associated with various kinds of page items such as graphic frames (kSplineItemBoss), pictures (kImageItemBoss, etc.), and groups (kGroupItemBoss). They can each have distinct standoff properties. IStandOffData::QueryStandOffGeometry 1 0..1 IStandOffData «boss class» layout::kPageItemBoss 1 «boss class» kStandOffPageItemBoss IStandOffItemData IPathGeometry 1 IStandOffItemData::QueryPageItem Represents the contour of the text wrap «boss class» layout::kDrawablePageItemBoss Other kinds of page items not shown on this diagram can also have a standoff. «boss class» graphics::kImageBaseItem «boss class» layout::kSplineItemBoss Text Fundamentals «boss class» layout::kGroupItemBoss «boss class» graphics::kImageItem 349 Text Fundamentals Text presentation Properties of a standoff are found in IStandOffData on the page item with the standoff. Use IStandOffData::GetMode to obtain the kind of text wrap and IStandOffData::GetMargin to get the offsets. Each page item has distinct standoff applied, so the page item can be a graphic frame (kSplineItemBoss), a group (kGroupItemBoss), or another type. When a text wrap is applied, a standoff boss class kStandOffPageItemBoss is associated with the owning page item. The standoff boss class is not part of the page item instance hierarchy; you do not navigate to it using IHierarchy. Instead, use IStandOffData::QueryStandOffGeometry to access the standoff boss class. The kStandOffPageItemBoss boss class has a path geometry that represents the contour of the standoff, and text in a text frame wraps to this contour. Text on a path Text on a path allows text to flow along the contour of a spline (kSplineItemBoss). Text on a path frame has an inport and an outport. As a result, you can thread text in other frames to and from it. Figure 148, Figure 149, and Figure 150 show the objects involved in text on a path. FIGURE 148 Text on a path kSplineItemBoss Inport 350 kTOPSplineItemBoss kMultiColumnItemBoss kTOPFrameItemBoss Outport Text Fundamentals Text presentation FIGURE 149 Instance diagram for text on a path Text on a path frame IMainItemTOPData::GetTOPSplineItemUID «boss class» path : layout::kSplineItemBoss UID = 144 ITOPSplineData::GetMainSplineItemUID «boss class» text on a path spline : kTOPSplineItemBoss UID = 184 IHierarchy::QueryParent IHierarchy::QueryChild(0) «boss class» controller : kMultiColumnItemBoss UID = 185 IHierarchy::QueryParent IHierarchy::QueryChild(0) «boss class» text on path frame item : kTOPFrameItemBoss UID = 186 IFrameList::QueryNthFrame(0) ITextFrameColumn::QueryFrameList «boss class» frame list : kFrameListBoss UID = 182 ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» story : The Text Model::kTextStoryBoss UID = 166 Text Fundamentals 351 Text Fundamentals Text presentation FIGURE 150 Structure of text on a path frame IMainItemTOPData::GetTOPSplineItemUID 1 1 «boss class» layout::kSplineItemBoss Represents the contour along which the text flows IMainItemTOPData IPathGeometry Text on a path frame 1 0..1 owns text on path «boss class» kTOPSplineItemBoss ITOPSplineData::GetMainSplineItemUID 1 1 1 ITOPSplineData IHierarchy::QueryParent IHierarchy::QueryChild «boss class» kMultiColumnItemBoss 1 1 IHierarchy::QueryParent IHierarchy::QueryChild -IMainItemTOPData::GetTOPTextContentUID «boss class» kTOPFrameItemBoss 1 ITOPFrameData «boss class» kFrameItemBoss 1..* Text on a path frame is a special kind of text frame. It is represented by three associated boss classes: kTOPSplineItemBoss, kMultiColumnItemBoss, and kTOPFrameItemBoss. Note that you will not find these boss classes on the hierarchy (IHierarchy) that owns the kSplineItemBoss. Instead, they can be accessed by interface IMainItemTOPData on the owning spline. IFrameList::QueryNthFrame ITextFrameColumn::QueryFrame 1 «boss class» kFrameListBoss 1 1 ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» The Text Model::kTextStoryBoss Text on a path can be associated with any spline (kSplineItemBoss). The structure of text on a path frame parallels that of a normal text frame. It is represented by three associated boss classes: kTOPSplineItemBoss, kMultiColumnItemBoss, and kTOPFrameItemBoss. You can navigate from a spline (kSplineItemBoss) to any associated text on a path (kTOPSplineItemBoss) using the IMainItemTOPData interface. You can navigate back using the ITOPSplineData interface. After you have an interface on the kTOPSplineItemBoss, you can navigate up and down the text on a path frame using IHierarchy. Figure 151 and Figure 152 show a text frame that also has text on a path running along its contour. In this example, the text displayed inside the frame and the text that runs its contour have distinct underlying stories. If they were threaded, they would be associated with the same story. 352 Text Fundamentals Text presentation FIGURE 151 Text frame with text on a path FIGURE 152 Instance diagram for text frame with text on a path Text frame Text on a path frame IMainItemTOPData::GetTOPSplineItemUID «boss class» graphic frame : layout::kSplineItemBoss UID = 183 ITOPSplineData::GetMainSplineItemUID IHierarchy::QueryParent IHierarchy::QueryChild(0) «boss class» controller : kMultiColumnItemBoss UID = 184 IHierarchy::QueryParent IHierarchy::QueryChild(0) «boss class» column 1 : kTOPFrameItemBoss UID = 186 IFrameList::QueryNthFrame(0) ITextFrameColumn::QueryFrameList «boss class» frame list : kFrameListBoss UID = 181 ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» story : The Text Model::kTextStoryBoss UID = 165 Text Fundamentals «boss class» text on path spline : kTOPSplineItemBoss UID = 205 IHierarchy::QueryParent IHierarchy::QueryChild(0) «boss class» controller : kMultiColumnItemBoss UID = 206 IHierarchy::QueryParent IHierarchy::QueryChild(0) «boss class» text on path frame item : kTOPFrameItemBoss UID = 207 IFrameList::QueryNthFrame(0) ITextFrameColumn::QueryFrameList «boss class» frame list : kFrameListBoss UID = 203 ITextModel::QueryFrameList IFrameList::QueryTextModel «boss class» story : The Text Model::kTextStoryBoss UID = 187 353 Text Fundamentals Text presentation The wax The output of text composition is called the wax. The wax is responsible for drawing and hit testing the text of a story. The term “wax” comes from the manual paste-up process conventionally used to create magazine and newspaper pages before the advent of interactive pagination software. In the old process, typeset columns of text (galleys) were received from the typesetter. The galleys were run through a waxer, cut into sections, and positioned on an art board. Wax was used as an adhesive to stick the sections on the art board. The art board in InDesign is a spread, and you can think of the galleys as text frames. The typeset columns of text are the wax generated by text composition. The wax adheres—fixes—the position of a line of text within a frame. Wax strand, wax line, and wax run The frame list (kFrameListBoss) manages the wax for a story by means of the wax strand (IWaxStrand interface). The wax strand owns a collection of wax lines that contain wax runs, as shown in Figure 153. FIGURE 153 Class diagram of the wax kTextStoryBoss kFrameItemBoss 1 1 0..1 The wax kFrameListBoss 1 IWaxStrand 0..m Collection (kWaxLineBoss) 1 0..m kWaxILGRunBoss 354 1 0..m 1 0..m kWaxTextRunBoss 0..m Collection (TCY, WarichuuSet, etc.) Text Fundamentals Text presentation The wax is organized as a hierarchy of collections and leaf runs. The most common case is a series of wax lines, each with a collection of wax runs. A wax line is created for each line of text in a frame. A wax run is created each time the appearance of the text changes within the line. Examples of this include changes in point size, changes in font, and the interruption of the flow of text in a line because text wrap causes text to flow around another frame. The IWaxStrand interface on kFrameListBoss owns all wax lines for a story and is the root of the wax tree. The IWaxIterator and IWaxRunIterator iterator classes provide access to wax lines and wax runs. kWaxLineBoss typically represents the wax for one line of text. (Warichuu is an exception to this, where the Warichuu set contains multiple lines; all lines in the Warichuu set relate to one kWaxLineBoss object.) Each line owns its wax runs, collections of wax runs, or combination of runs and collections of runs. kWaxLineBoss provides access to its children through the IWaxCollection interface. Any boss that supports the IWaxCollection interface is a parent in the wax hierarchy to boss objects that support the IWaxRun interface. A boss can support both the IWaxCollection and IWaxRun interfaces, creating levels in the hierarchy. kWaxTextRunBoss is the object that represents the wax for ordinary text. This object stores the information needed to render the glyphs and provides the interfaces that draw, hit test, and select the text. kWaxILGRunBoss represents the wax for inline frames. Inline frames allow frames to be embedded in the text flow. An inline frame behaves as if it were one character of text and moves along with the text flow when the text is recomposed. kWaxILGRunBoss provides the drawing, hit testing, and selection behavior for inline frames. For a complete list of wax-run boss classes, see the API reference documentation for IWaxRun. Examples of the wax This section describes the wax generated for some sample text frames. To recreate these examples, use the Text tool to create the frames. If you use another tool, like the place gun or a graphic frame tool, the inner coordinate spaces for the frames will be different from those illustrated. For simplicity, use a sample page size 200 points wide and 100 points deep, and format text using 8-point type, the Times Regular font, and 10-point leading. All text is composed by the Adobe Paragraph Composer in a horizontal text frame. Single line with no format changes The wax generated for a single line of text with no format changes is shown in Figure 154. This example has a frame 200 points wide and 30 points deep, containing one line of 8-point Times Regular text with 10-point leading. The first baseline offset setting for the frame is set to leading. This forces the baseline of the first line of text in the frame to be offset from the top of the frame by a distance equal to the leading value for the text (10 points). Text Fundamentals 355 Text Fundamentals Text presentation FIGURE 154 Wax for single line with no format changes left=-100, top=-15 Leading -5 Width WaxLine X=-100 Y=-5 Width=55.76 Origin=0 Span=17 right=100, bottom= 15 WaxRun X=0 Y=0 Width=55.76 Origin=0 Span=17 Each node in the wax tree records its position, its width, and a reference to the characters in the text model it describes. The origin records the index into the text model to the first character in the node. The span records the number of characters in the node. Wax lines record their position in the inner coordinate space of the frame in which they are displayed. Wax runs record their position as an offset relative to the position of the wax line. Additional information is stored specific to the type of node—wax line or wax run. Figure 155 exposes some additional data in the wax. A wax line stores the leading for the line. A wax run stores font name, a font-transformation matrix, glyph information, and other data necessary to describe how the text is to be drawn. A glyph is an element of a font. 356 Text Fundamentals Text presentation FIGURE 155 Information stored in the wax -100,-15 100,15 WaxLine X=-100 Y=-5 Width=55.76 Origin=0 Span=17 Leading=10 WaxRun X=0 Y=0 Width=55.76 Transformation matrix Origin=0 for 8-point text Span=17 FontName=Times-Roman FontMatrix=[8 0 0 8 0 0] GlyphIDs=[0x24 0x4f 0x4c 0x48 0x51 0x56 0x3 0x44 0x51 0x47 0x3 0x28 0x44 0x55 0x57 0x4b 0xffffffff ] GlyphWidths=[5.78 2.22 2.22 3.55 4.00 3.11 2.00 3.55 4.00 4.00 2.00 4.89 3.55 2.66 2.22 4.00 2.00] When a character is composed, its character code is mapped to its corresponding GlyphID from the font being used to display the character. The font provides the initial width of a glyph at a particular point size. This width may be adjusted by composition to account for letter spacing, word spacing, and kerning. The GlyphID values and their widths after composition are stored in the wax run, as shown in Figure 155. Generation of wax runs Wax runs are generated for each set of format changes or line breaks that occur in the rendered text. Figure 156 illustrates the effect of applying text attributes that change text format. Text Fundamentals 357 Text Fundamentals Text presentation FIGURE 156 Wax for single line with format changes -100,-15 100,15 WaxLine X=-100 Y=-5 Width=60.33 Origin=0 Span=17 WaxRun X=0 Y=0 Width=22.89 Origin=0 Span=7 FontName=Times-Roman FontMatrix=[8 0 0 8 0 0] WaxRun X=22.89 Y=0 Width=16.12 Origin=7 Span=3 FontName=Times-Bold FontMatrix=[10 0 0 10 0 0] WaxRun X=39.01 Y=0 Width=21.32 Origin=10 Span=7 FontName=Times-Roman FontMatrix=[8 0 0 8 0 0] UnderlineMode=kUnderlineSingle Figure 156 shows how a wax run is created each time the text attributes specify the appearance of the text is to change. The arrows show the correspondence between the text drawn in the frame and the wax run that describes its appearance and location. A distinct wax run would be required for the following: z Each time the appearance of the text changes within the line. z Each line of text that appears in the parcel list for a story. z Each side of a line that is interrupted, either by using an irregular-shaped frame or by overlapping a page item with wrap turned on within the frame. Text adornments Text adornments provide a way for plug-ins to adorn the wax (composed text). Text adornments give plug-ins the opportunity to do additional drawing when the wax in a frame is drawn. The wax draws the text and calls the text adornments it is aware of to draw. For this to occur, the adornment must be attached to the wax. Text adornments are boss objects attached by ClassID to an individual wax run. When the run is drawn, text adornments are given control using the ITextAdornment interface. 358 Text Fundamentals Text presentation Calls to the ITextAdornment::Draw method are ordered by the priority value returned by the ITextAdornment::GetDrawPriority method. Higher-priority adornments (smaller numbers) are called before lower-priority adornments (larger numbers). Text adornments cannot influence how text is composed; for example, they cannot influence how characters are built into wax lines and wax runs by the text-composition subsystem. Instead, text adornments augment the appearance of the text. A text adornment controls whether the adornment is drawn in front of or behind the text. There are two types of text adornments: local and global. Local text adornments A local text adornment is controlled by one or more text attributes. A local text adornment provides visual feedback of the text the text attributes control. For example, an adornment can highlight the background on which the text is drawn or strike out text by drawing a line in the foreground. The text attribute controls the process by interacting with text composition and associating the adornment with a drawing style (see IDrawingStyle and kComposeStyleBoss). This causes the text composer to attach the adornment to a wax run (see IWaxRenderData in “The wax” on page 354). Table 91 shows the main text adornments used by the application and the text attributes that control them. TABLE 91 Text adornments and associated text attributes Adornment classID Attribute classID Description kTextAdornmentIndexMarkBoss kTAIndexMarkBoss Index mark kTextAdornmentKentenBoss kTAKentenSizeBoss, etc. Adorns text for emphasis kTextAdornmentRubyBoss kTARubyPointSizeBoss, etc. Annotates base text kTextAdornmentStrikethruBoss kTextAttrStrikethruBoss Strikes through text kTextAdornmentUnderlineBoss kTextAttrUnderlineBoss Underlines text kTextHyperlinkAdornmentBoss kHyperlinkAttributeBoss Hyperlink mark To add a local text adornment, first add a new text attribute. In more complex situations, use multiple text attributes to control one text adornment. For example, kTAKentenSizeBoss, kTAKentenRelatedSizeBoss, kTAKentenFontFamilyBoss, and kTAKentenFontStyleBoss collectively control the kenten adornment implemented by the kTextAdornmentKentenBoss. Local text adornments are attached to a drawing style and subsequently to an individual wax run. These adornments always are called to draw, although they can choose not to draw anything. Figure 157 shows the sequence of calls that result in an adornment being associated with a particular wax run. Text Fundamentals 359 Text Fundamentals Text presentation FIGURE 157 Sequence for adding an adornment to a specific wax run Composition (abstract) Creates kComposeStyleBoss to hold the exact value of all attributes as they apply to an individual run of text IAttrReport (kSomeTextAttrBoss) IDrawingStyle (kComposeStyleBoss) IWaxRun (kWaxTextRunBoss) create TellComposition(ICompositionStyle* style, IDrawingStyle* draw) AddTextAdornment(ClassID attrID, ClassID adornmentID) Adornment ClassID added to the wax run AddAdornment(ClassID id) The composition subsystem invokes each attribute active for the run of text, allowing the attribute to p articipate in the composition process. The attribute can specify adornments to be added to the drawing style. These adornments will be given the opportunity to participate in the drawing process. The composition subsystem calls the IAttrReport::TellComposition method of each attribute that applies to a particular range of text. This gives the attribute a chance to interact with the composition subsystem. This interaction includes the registering of adornments that are to be associated with the wax and called when the wax is drawn (IDrawingStyle::AddTextAdornment). The adornments are attached to the wax as ClassIDs (IWaxRun::AddAdornment); i.e., the adornments are not instantiated at this point. Figure 158 shows how adornments associated with a wax run are instantiated and called to draw. 360 Text Fundamentals Text presentation FIGURE 158 Draw Subsystem Sequence for local-adornment drawing IParcelShape (kFrameItemBoss) ITextParcelList (kFrameListBoss) IWaxLineShape (kWaxLineBoss) IWaxRunText (kWaxTextRunBoss) IWaxRun ITextAdornment (kWaxTextRunBoss) (kSomeAdornmentBoss) Draw Draw Draw Draw GetAdornments create Draw Gets the list of adornments (classID) held by the wax run The Draw signal propagates to the wax run (IWaxRunText on kWaxTextRunBoss). The wax run (IWaxRun on kWaxTextRunBoss) is interrogated for the set of adornments registered through composition, as shown in Figure 157. Each adornment (ITextAdornment) is created on whichever boss class it is represented on, and the Draw method is called. It is possible to associate a data interface (ITextAdornmentData) during registration (IAttrReport::TellComposition). This interface allows control over whether the adornment is associated with wax runs. Global text adornments Global text adornments are attached to all wax runs, though they never have run-specific adornment data. Global text adornments provide the ability to draw something without requiring the text to be recomposed. Unlike local text adornments, global text adornments do not need to be attached to individual wax runs to draw; however, global text adornments are asked if they are active before they are called to draw. For example, the Show Hidden Characters feature is implemented using a global text adornment, kTextAdornmentShowInvisiblesBoss. The adornment behaves as if it is attached to all runs, but is called only when the adornment requests draw. Text Fundamentals 361 Text Fundamentals Text presentation Table 92 lists global text adornments. TABLE 92 Global text adornments Adornment boss Description kTextAdornmentHJKeepsVBoss Highlights keeps violations. kTextAdornmentMissingFontBoss Highlights missing fonts. kTextAdornmentMissingGlyphsBoss Highlights missing glyphs. kDynamicSpellCheckAdornmentBoss Squiggle line to mark spell checks. kTextAdornmentShowInvisiblesBoss Shows hidden characters. kPositionMarkerLayoutAdornmentBoss Draws position marker. kTextAdornmentShowKinsokuBoss Shows Japanese character line break. kTextAdornmentShowCustomCharWidthsBoss Marks character width as a filled rectangle. kXMLMarkerAdornmentBoss XML marker. Global text adornments are service providers. The ServiceID is kGlobalTextAdornmentService. Global text adornments aggregate the IK2ServiceProvider interface and use the default implementation kGlobalTextAdornmentServiceImpl. Global adornments have the opportunity to participate in drawing if they are enabled. Figure Figure 159 shows the sequence of events that cause IGlobalTextAdornment::Draw to be called. For brevity, the calls to the adornment to determine whether it is enabled (IGlobalTextAdorbment::GetIsActive) and to access the ink bounds of the adornment (IGlobalTextAdornment::GetInkBounds) are not shown. 362 Text Fundamentals Text presentation FIGURE 159 Draw Subsystem Sequence diagram for drawing of global adornments IParcelShape (kFrameItemBoss) IK2Servi ceReg istry (kSessionBoss) ITextParcelList (kFrameListBoss) IWaxLineShape (kWaxLineBoss) IWaxRunText (kWaxTextRunBoss) IGlobalTextAdornment (kSomeAdornmentBoss) Draw GetNthServiceProviderID(kGlobalTextAdornmentServiceID) Draw Draw Draw Draw Builds a list of global adornments requesting to be drawn Invokes Draw on all adornments on the list previously constructed When a frame (IParcelShape on kFrameItemBoss) is instructed to draw, it queries the service registry (IK2ServiceRegistry on kSessionBoss) for the set of global text adornments that are enabled (IGlobalTextAdornment::GetIsActive). The frame calls Draw on the parcel list (ITextParcelList on kFrameListBoss), which causes the wax line (IWaxLineShape on kWaxLineBoss) and wax run (IWaxRunText on kWaxTextRunBoss) Draw methods to be called. During the drawing of the wax run, the global adornments built up previously (Draw from IParcelShape on kFrameItemBoss) have their Draw method called. Compare Figure 159 with Figure 158. The set of global adornments are global to the document (maintained by the service registry), whereas local adornments are local to a specific wax run. Text Fundamentals 363 Text Fundamentals Text composition Text composition This section describes the process of creating the final rendered text. It includes information for software developers who want to develop custom composition engines. Text composition is the process of converting text content into its composed representation, the wax. The text-composition subsystem flows text content from a story thread maintained by a story into a layout represented by parcels in a parcel list. Story threads are described in “Story threads” on page 320; parcels and the wax, in “Text presentation” on page 331. Figure 160 is an overview of text composition. FIGURE 160 Text composition Text layout Frames/ parcels The wax Wax lines Text composition Fonts Glyphs Story thread characters and text attributes The text model Figure 161 shows a sample text frame with no format changes. The figure shows the objects representing the story, the frame, and the composed text; it does not show the details of how the text actually gets composed. 364 Text Fundamentals Text composition FIGURE 161 Sample text frame with no formatting changes kTextStoryBoss ITextModel ITextStoryThread kSplineItemBoss IHierarchy kFrameListBoss IFrameList IParcelList ITextParcelList ITextParcelListData IWaxStrand kWaxLineBoss kWaxLineBoss IWaxLine kWaxLineBoss IWaxLine IWaxLine kWaxTextRunBoss kWaxTextRunBoss kWaxTextRunBoss IWaxRun IWaxRun kMultiColumnItemBoss IHierarchy kFrameItemBoss IHierarchy IParcel ITextTiler ITextGrid ITextFrameColumn Text composition creates the wax lines (kWaxLineBoss) and their associated wax runs (kWaxTextRunBoss) using the primary story thread’s content and layout as input. Wax lines are added to the wax strand (IWaxStrand). Text composition also maintains the range of characters displayed in each parcel/frame (see “Span” on page 342). Text Fundamentals 365 Text Fundamentals Text composition Phases of text composition There are two distinct phases of text composition: z Damage refers to changes that invalidate the wax for a range of composed text. Inserting text and modifying frame size are examples of changes that cause damage. This is described further in “Damage” on page 367. z Recomposition is the process that repairs the damage and updates the wax to reflect the change. This is described further in “Recomposition” on page 369. Text composition toggles the wax between the states shown in Figure 162. The flow of damage and recomposition is shown in Figure 163. FIGURE 162 The wax state Start Recomposition is completed. Damaged. Do recomposition. Not damaged. The text model or text layout is updated. 366 Text Fundamentals Text composition FIGURE 163 Plug-in Damage and recomposition, the phases of text composition Update The text model MarkDamage Characters + text attributes Update Recompose MarkDamage Fonts Glyphs Text composition Text layout Parcels/ frames MarkDamage Wax lines The wax DetectDamage Recompose Background composition Figure 163 shows a plug-in can update the text model or text layout, causing the wax (the composed representation of the text) to be damaged. The text-composition subsystem exposes interfaces that mark the damaged story, frame parcels, and wax. The damage-recording flow is represented by dotted lines in Figure 163. The text-composition subsystem also exposes interfaces that allow text to be recomposed. In the figure, the recomposition flow is represented by solid lines. Background composition (see “Background composition” on page 371) is a separate process that drives text composition. Background composition runs as an idle task when the application has no higher-priority tasks. Consider the example in which the plug-in shown in Figure 163 is the text editor. In response to typing, the plug-in processes a command to insert the typed characters into the text model. This command calls text-composition interfaces that record the damage caused. Background composition detects the damage and recomposes the affected text. Damage Damage is defined as the changes that invalidate the wax for a range of composed text. Damage is recorded by marking the affected stories, parcels, frames, and wax. The damage indicates where recomposition is required and the type of damage that has to be repaired. The change counter on the frame list is incremented whenever something happens that causes damage. No notification is broadcast when the change counter is incremented, so the change Text Fundamentals 367 Text Fundamentals Text composition cannot be caught immediately; however IFrameList::GetChangeCounter returns a counter that is incremented (and eventually rolls over) each time any parcel in any frame in the frame list goes from undamaged to damaged, indicating some text in the frame list was damaged and must be recomposed. Damage drives and optimizes the recomposition process. For example, recomposition can shuffle existing wax lines between frames to repair damage and avoid recomposing the text from scratch. Based on the action that caused the damage, there are the following categories of damage: z Insert damage occurs when text is inserted. z Delete damage occurs when a range of text is deleted. z Change damage occurs when a range of text is replaced or the text attributes that apply to a range of text are modified. z Resize damage occurs when a frame is resized. z Rect damage occurs when text wrap or text inset is applied. z Move damage occurs when a frame is moved. z Destroyed damage occurs when some combination of the above types of damage occurs. When this happens, the existing wax for the affected range must be recomposed. z Keeps damage occurs when a line must be pushed to the start of a new frame to eliminate orphans and widows. Orphans and widows are words or single lines of text that become separated from the other lines in a paragraph (see Figure 164). An orphan occurs when the first line of a paragraph becomes separated from the rest of the paragraph body. A widow occurs when the last line of a paragraph becomes separated from the rest of the paragraph body. FIGURE 164 Orphan (left) and widow (right) Check for damage before relying on the information stored in the wax or the frame spans (see “Span” on page 342). If your plug-in detects damage, it can either stop with a suitable error or recompose the text. 368 Text Fundamentals Text composition Damage API To detect damage, use the interface methods shown in Table 93 to detect damage. The damage bookkeeping methods used to record the damage are not called directly by third-party plugins; the text subsystem calls these methods as necessary in response to changes that affect text. TABLE 93 Damage-inquiry interfaces and methods Interface Method IStoryList CountDamagedStories, GetLastDamagedStory, GetNthDamagedTextModelUID IFrameList GetFirstDamagedFrameIndex IFrameDamageRecorder GetCompState IWaxLine IsContentDamaged, IsDamaged, IsDestroyed, IsGeometryDamaged, IsKeepsDamaged ITextParcelListData GetFirstDamagedParcel, GetParcelIsDamaged ITextParcelList GetFirstDamagedParcel, GetIsDamaged Recomposition Recomposition is the process of converting text from a sequence of characters and attributes into the wax (fully formatted paragraphs ready for display). The components of recomposition are as follows: z Interfaces that control text composition. z The wax strand that manages the wax for the story. z Paragraph composers that create the wax for a line or paragraph. Recomposition API To request recomposition, use the interface methods shown in Table 94. TABLE 94 Recomposition interfaces and methods Interface Method Description IFrameList QueryFramesContaining Helper method that causes recomposition. IFrameListComposer RecomposeThruNthFrame, RecomposeThruTextIndex Controls recomposition of frames in the frame list (kFrameListBoss). The methods delegate to the parcel list composer (ITextParcelListComposer). IFrameComposer RecomposeThruThisFrame Controls recomposition of a frame. The methods delegate to the wax strand (IWaxStrand), which does the real work. Text Fundamentals 369 Text Fundamentals Text composition Interface Method Description ITextParcelListComposer RecomposeThruNthParcel, RecomposeThruTextIndex Controls recomposition of parcels in a parcel list. The methods delegate to the wax strand (IWaxStrand), which does the real work. IGlobalRecompose RecomposeAllStories, SelectiveRecompose, ForceRecompositionToComplete Provides methods that can be used to force all stories to recompose. This interface marks damage that forces recomposition to recompose the damaged element, even though they were not actually changed. The interfaces and methods in Table 95 are not normally called by third-party plug-ins but play a central role in the control of recomposition. TABLE 95 Recomposition interfaces and key methods Interface Method See IFrameComposer RecomposeThisFrame “Wax strand” on page 370 IRecomposedFrames BroadcastRecomposition Complete “Recomposition notification” on page 372 IParagraphComposer Recompose, RebuildLineToFit “Paragraph composers” on page 371 Wax strand The wax strand (IWaxStrand) manages the wax for a story and is responsible for updating the wax to reflect changes in the text model or text layout. The wax strand controls the existing wax and determines when and where a paragraph composer needs to be used to create new wax. The wax strand also manages the overall damage-recording process. The main text-recomposition methods are IFrameComposer::RecomposeThisFrame. The recomposition methods on interfaces, such as IFrameList and IFrameListComposer, delegate the actual work to these IWaxStrand methods. NOTE: These methods are not called directly by third-party plug-ins. The lifecycle of the wax is as follows: 1. The wax strand is informed a range in the text model was changed. In response, the wax strand locates the wax lines that represent this range and marks them damaged. 2. On the next recomposition pass, the wax strand finds the first damaged wax line in the story and asks a paragraph composer to recompose it. 3. The paragraph composer creates new wax lines and applies them to the wax strand (RecomposeHelper::ApplyComposedLine). RecomposeHelper is a helper class within IParagraphComposer, so any existing wax lines that represent the same range in the text model are destroyed. 370 Text Fundamentals Text composition 4. The wax strand repeats this process until it finds no more damaged wax lines or reaches the end of the frame. Paragraph composers A paragraph composer (IParagraphComposer) takes up to a paragraph of text and arranges it into lines to fit a layout. The paragraph composer creates the wax that represents the composed text. Plug-ins can introduce new paragraph composers. For more information, see “Implementation notes for paragraph composers” on page 372. The text-composition architecture is designed for paragraph-based composition. The most significant implication of this design is that any change to text or attributes results in at least one paragraph’s composition information being re-evaluated. For example, inserting one character into a paragraph potentially can result in changes to any or all the line breaks in the paragraph, including those preceding the inserted character. Shuffling Avoiding recomposition of text and simply moving existing wax lines up or down is called shuffling. The performance improvement gained by shuffling is significant. The wax strand can determine if a wax line was damaged because of something that occurred around the wax line and not because the range of text it represents changed, in which case the wax strand knows that the net result of recomposing the text is simply to move the wax line up or down. The content of the wax line after recomposition is identical to its current content. For example, if you select and delete an entire paragraph of text, the next paragraph has not changed and does not need to be recomposed. By pulling the following paragraph up to the position occupied by the deleted paragraph, the wax strand avoids the cost of recomposition. When shuffling, the wax strand implements some of the behaviors of a paragraph composer, like dealing with space before and after paragraph attributes. Vertical justification Vertical justification moves wax lines up and down within the container that displays them, according to rules. For example, the lines can be justified to the top, center, or bottom. They also can be justified to fill the available space. The wax strand is responsible for vertical justification, and this mechanism is not extensible by third-party plug-ins. Background composition Background composition looks for damage, then fixes it by calling for recomposition. Background composition runs in the background as an idle task (IID_ICOMPOSITIONTHREAD on kSessionBoss) and recomposes text. Each time background composition is called, it performs the following actions in priority order: Text Fundamentals 371 Text Fundamentals Text composition 1. Recomposes visible frames of damaged stories in the frontmost document. 2. Recomposes other damaged stories in the frontmost document. 3. Recomposes damaged stories in other open documents. The actions are performed until the time slice allocated for background text composition expires. Background composition requests recomposition by calling the RecomposeUntil method on IFrameListComposer. Recomposition transactional model Plug-ins use commands to update the input data that drives text composition (the text model and text layout). The commands cause damage to occur. Recomposition subsequently recomposes the text and generates the wax to reflect the changes. Recomposition does not execute within the scope of a command; instead, the wax strand begins and ends a database transaction around the recomposition process. This means recomposition cannot directly be undone; however, the commands used to update the input data are undoable. Undo causes damage, and recomposition repairs it to ensure the wax (the text displayed) reflects the state of the text model and text layout. Recomposition notification The IRecomposedFrames interface on the frame list (kFrameListBoss) keeps track of which frames are recomposed, so text frame observers can be notified when recomposition completes. When the BroadcastRecompositionComplete method is called, each affected column (kFrameItemBoss) receives notification that it was recomposed. Observers attach to the kFrameItemBoss in which they are interested and then watch for the Update method to be called with theChange == kRecomposeBoss and protocol==IID_IFRAMECOMPOSER. Implementation notes for paragraph composers This section provides more in-depth background for software developers developing a custom paragraph composer for the application. Paragraph composers A paragraph composer (IParagraphComposer) takes up to a paragraph of text, arranges it into lines to fit a layout, and creates the wax that represents the text it composed. Plug-ins can introduce new paragraph composers. The user selects the composer to be used for a paragraph from the menu on the Paragraph panel (see Figure 165) or by using the Paragraph Styles palette. Selecting a paragraph composer sets the kTextAttrComposerBoss paragraph attribute to indicate which paragraph composer to use. 372 Text Fundamentals Text composition FIGURE 165 Setting the paragraph composer Hyphenation and justification (HnJ) The term “hyphenation and justification” (‘HnJ’) often is used in computer systems to refer to breaking of text into lines and spacing of text so it aligns with the margins. This term is not used in this application’s API or documentation; however, the role performed by an HnJ system is similar to the role of a paragraph composer. Hyphenation is intimately associated with line breaking. In this application, the role is split out and implemented by a hyphenation service (IHyphenationService). A paragraph composer that needs to hyphenate a word uses a hyphenation service. A paragraph composer’s environment Paragraph composers are called by the text-composition subsystem. When text is to be recomposed, the wax strand examines the paragraph attribute kTextAttrComposerBoss that specifies the paragraph composer to be used, locates it through the service registry, and calls the IParagraphComposer::Recompose method. This call gives the paragraph composer a context stored in the helper class in which to work. virtual bool16 Recompose(RecomposeHelper* helper) The RecomposeHelper class is a wrapper of the story being recomposed. It stores information like the story’s compose scanner, tiler, starting index, text span, and position. The RecomposeHelper class definition is in IParagraphComposer.h. Figure 166 shows an example of a paragraph composer called to compose text. Text Fundamentals 373 Text Fundamentals Text composition FIGURE 166 Paragraph-composer environment -100,-15 100,15 kFrameListBoss IWaxStrand helper->ApplyComposedLine Wax lines and runs Other parcel list boss kTextCellContentBoss kTextStoryBoss kFrameListBoss helper->GetComposeScanner Recompose Characters and effective attribute values characters=”Aliens “ fontName=Times-Roman, pointSize=8 point, leading= 10 points IParagraphComposer Tiles firstBaselineOffset=leading tile [0] = [-100, -15, 100, -5] Paragraph composer boss class The following steps occur: 1. The paragraph composer composes the text and creates at least one wax line in the helper. 2. The paragraph composer accesses the character-code and text-attribute data for the story, using the IComposeScanner interface acquired from helper->GetComposeScanner. 3. The paragraph composer determines the areas in a line where glyphs can flow, using IParagraphComposer::Tiler. 4. The wax lines are applied to the IWaxStrand interface by calling helper->ApplyComposedLine. NOTE: Both yPosition and tiles are specified in the inner bounds (coordinate system) in RecomposeHelper. The scanner and drawing style The scanner (IComposeScanner) provides access to both character and formatting (text attributes) information from the text model, as shown in Figure 167. The drawing style (interface IDrawingStyle) represents the effective value of text attributes at a given index in the text 374 Text Fundamentals Text composition model. The drawing style cached by interfaces on kComposeStyleBoss considerably simplifies accessing text-attribute values. These interfaces remove the need to resolve text-attribute values from their representation in the text model and the text styles it references. A drawing style applies to at least one character. The range of characters it applies to is a run. For more information on styles and overrides, see “Text formatting” on page 324. FIGURE 167 The scanner and drawing style kTextDataStrandBoss kParaAttrStrandBoss kCharAttrStrandBoss kStyleBoss kTextStoryBoss kStyleBoss Text attributes IComposeScanner kComposeStyleBoss IDrawingStyle ICompositionStyle IHyphenationStyle IJustificationStyle Drawing style (effective attribute values) Characters Paragraph composer boss class IParagraphComposer Fonts and glyphs Fonts contain the glyphs that display characters for a typeface at a particular size. Paragraph composers use the drawing style (IDrawingStyle) to find the font to be used. The font APIs provide the metrics required to compose the text into lines composed of a run of glyphs for each stylistic run of text. A font represents a typeface with a given size and style. A typeface, like Times, is the letters, numbers, and symbols that make up a design of type. A glyph is a shape in a font that is used to represent a character code on screen or paper. The most common example of a glyph is a letter, but the symbols and shapes in a font like ITC Zapf Dingbats also are glyphs. For more information, see Figure 168 and “Fonts” on page 389. Text Fundamentals 375 Text Fundamentals Text composition FIGURE 168 Accessing a font kComposeStyleBoss QueryFont IPMFont IDrawingStyle QueryFontInstance IFontInstance Tiles Tiles (IParagraphComposer::Tiler) represent the areas on a line into which text can flow. Normally, there is only one tile on a line; however, text wrap may cause intrusions that break up the places in the line where text can go. The tiler takes care of this, as well as accounting for the effect of irregularly shaped text containers. Intrusions are the counterparts of tiles. Intrusions are not the inverse of tiles: they do not specify the areas in the line where text cannot be flowed. From the perspective of ITextTiler, an intrusion is a horizontal band within a frame, in which text flow within the bounding box of the frame may be interrupted. Intrusions can be used to optimize recomposition. An intrusion is a flag that indicates that text cannot be flowed into the entire width of a line. Intrusions are caused by text wrap and nonrectangular frames. The tiles returned for a line depend on the y position where they are requested, their depth, and their minimum width. The intrusions and tiles for some sample text frames are shown in Figure 169 through Figure 173. FIGURE 169 Frame FIGURE 170 Frame 376 Text frame with no intrusions Intrusions(none) Tiles Effect of image frame with text wrap Intrusions Tiles Text Fundamentals Text composition FIGURE 171 Effect of two images with text wrap Frame FIGURE 172 Tiles Intrusions Tiles Effect of text inset Frame FIGURE 173 Intrusions Effect of nonrectangular frame Frame Intrusions Tiles First-baseline offset The first-baseline offset setting controls the distance between the top of a parcel or frame and the baseline of the first line of text it displays. Some sample settings are shown in Figure 174. Text Fundamentals 377 Text Fundamentals Text composition FIGURE 174 First-baseline offset examples The setting controls the distance between the top inset of the frame and the baseline of the first line. Use the largest leading on the line. Leading Ascent Cap height Use the largest ascent on the line. This makes the top of the tallest glyph fall below the top inset of the frame. Use the largest Cap Height on the line. This makes the top of upper case letters touch the top inset of the frame. Control characters A paragraph composer can apply an appropriate behavior to correctly implement the semantic intent of many control characters. For a complete list of control-character codes, see TextChar.h in the API reference documentation. Inline frames Inline frames (kInlineBoss) allow frames to be embedded in the text flow. An inline frame behaves as if it were one text character and moves along with the text flow when the text is recomposed. The kTextChar_ObjectReplacementCharacter or kTextChar_Inline character is inserted into the text data strand to mark the position of the inline frame in the text. The inline frames are owned by the owned item strand (kOwnedItemStrandBoss) in the text model. Paragraph composers obtain the geometry of the frame associated with the kInlineBoss by using ITextModel to access this strand directly. Inline frames are represented in the wax by their own type of wax run, kWaxILGRunBoss. 378 Text Fundamentals Text composition Table frames Table frames (kTableFrameBoss) are owned items anchored on a kTextChar_Table character embedded in the text flow. Paragraph composers can and do compose text displayed in table cells.; however, they never compose (create wax for) the character codes related to tables (kTextChar_Table and kTextChar_TableContinued). When a paragraph composer encounters either of these characters, it should create wax for any buffered text and return control to its caller. Creating the wax During the process of building lines, a paragraph composer normally uses an intermediate representation of the glyphs, so it can evaluate potential line-break points and adjust glyph widths. The specific arrangement used depends on the overall feature set of the paragraph composer and is beyond the scope of this document. Once the line-break decisions are made, the paragraph composer must create wax lines and runs. For details of the mechanics of the creation of wax lines and runs, see “The wax” on page 354. Once created by a call to RecomposeHelper::QueryNewWaxLine, new wax lines are added to the wax strand for a story with the following call: RecomposeHelper::ApplyComposedLine(IWaxLine* newLine, int32 newTextSpan) Figure 175 shows an example of the wax generated by a paragraph composer. FIGURE 175 Wax for a single line with format changes -100,-15 100,15 WaxLine X=-100 Y=-5 Width=60.33 Origin=0 Span=17 WaxRun X=0 Y=0 Width=22.89 Origin=0 Span=7 FontName=Times-Roman FontMatrix=[8 0 0 8 0 0] Text Fundamentals WaxRun X=22.89 Y=0 Width=16.12 Origin=7 Span=3 FontName=Times-Bold FontMatrix=[10 0 0 10 0 0] WaxRun X=39.01 Y=0 Width=21.32 Origin=10 Span=7 FontName=Times-Roman FontMatrix=[8 0 0 8 0 0] UnderlineMode=kUnderlineSingle 379 Text Fundamentals Text composition Adobe paragraph composers Figure 176 shows the paragraph composers provided by the application under the Roman feature set. Figure 177 shows the paragraph composers provided under the Japanese feature set. Paragraph composers are implemented as service providers (IK2ServiceProvider) and can be located using the service registry. The ServiceID used to identify paragraph composers is kTextEngineService. FIGURE 176 Roman paragraph composers kParagraphComposerBoss IParagraphComposer IK2ServiceProvider GetServiceID=kTextEngineService GetName="HL Composer" FIGURE 177 kSingleLineComposerBoss IParagraphComposer IK2ServiceProvider GetServiceID=kTextEngineService GetName="HL Single" Japanese paragraph composers kJParagraphComposerBoss IParagraphComposer IK2ServiceProvider GetServiceID=kTextEngineService GetName="HL Composer J" kJSingleComposerBoss IParagraphComposer IK2ServiceProvider GetServiceID=kTextEngineService GetName="HL Single J" Key APIs Class diagram Paragraph composers are boss classes that implement IParagraphComposer, the interface called by the application to compose text. To be recognized as a text composer, the boss class also must implement a text-engine service (IK2ServiceProvider) with a ServiceID of kTextEngineService. The service also must provide a name (a translatable string) for the paragraph composer, which is displayed in the user interface. As output, composers generate wax lines (IWaxLine) and associated wax runs (IWaxRun) for up to one paragraph of text at a time. Figure 178 shows the class diagram of a custom paragraph composer. 380 Text Fundamentals Text composition FIGURE 178 Custom paragraph composer kYourParagraphComposerBoss IParagraphComposer IK2ServiceProvider GetServiceID=kTextEngineService GetName=”Your Composer" IParagraphComposer There are two distinct phases to text composition, and IParagraphComposer reflects these roles: z Positioning the line and, if necessary, deciding where text in the line should break. This information is represented persistently in the wax line. Features that affect line-break decisions belong here. This is the role of the Recompose method. z Positioning glyphs that represent the characters in the line and, if necessary, adjusting their widths. This information is represented by a set of wax runs associated with the wax line. Wax runs are not persistent and must be rebuilt for display when a wax line is read from disk. Features that affect glyph position (paragraph alignment, justification, letter spacing, word spacing, and kerning) belong here. This is the role of the RebuildLineToFit method, which regenerates composed text data from the minimal data stored on disk. Recompose is called when text needs to be fully recomposed. Each time this method is called, it should compose at least one line and at most one paragraph of text into the passed-in helper. RecomposeHelper actually does all the work, by creating wax starting from the character in the story indicated by RecomposeHelper::GetStartingTextIndex. The top of the area text flows into is given by RecomposeHelper::GetStartingYPosition, and composition is done using the supplied scanner and tiler. The wax lines generated as a result are applied to the given wax strand. NOTE: The paragraph composer is expected to create at least one wax line each time Recompose is called, even when overset text is what is being composed. RebuildLineToFit is called to regenerate the wax runs for a wax line from the minimal data stored on the disk. No line breaking or line positioning needs to be done here. IComposeScanner IComposeScanner is an interface aggregated on kTextStoryBoss. It provides methods that help access character and text-attribute information from the text model. It is the primary iterator for reading a story. Example 23 shows QueryDataAt, which gets a chunk of data from the text model starting from a given TextIndex. QueryDataAt is a primary method text composition uses to iterate through the text model. QueryDataAt returns a TextIterator, which has its own reference count on the chunk of data in the model, and thus makes the TextModel lifecycle independent of the com- Text Fundamentals 381 Text Fundamentals Text composition pose scanner cache. Optionally, QueryDataAt returns the drawing style and number of characters in the returned iterator. We recommend you always ask for the returned number of characters. EXAMPLE 23 IComposeScanner::QueryDataAt virtual TextIterator QueryDataAt(TextIndex position, IDrawingStyle** newstyle, int32* numChars) = 0; You also can acquire the drawing style by one of the methods listed in Example 24. For more information on the methods in IComposeScanner, see the API reference documentation. EXAMPLE 24 Acquiring IDrawingStyle from IComposeScanner virtual IDrawingStyle* GetCompleteStyleAt (TextIndex position, int32* lenleft = nil) = 0; virtual IDrawingStyle* GetParagraphStyleAt (TextIndex position, int32* lenleft = nil, TextIndex* paragraphStart = nil) = 0; QueryAttributeAt allows callers to query the effective value of one or more particular text attributes at a given position. For more details, see the API reference documentation. IDrawingStyle, ICompositionStyle, IHyphenationStyle, and IJustificationStyle IDrawingStyle provides access to text-attribute values like font, point size, and leading. If the text property you want is not in IDrawingStyle, you will find it in one of the other style interfaces on kComposeStyleBoss. For details, see the API reference documentation for kComposeStyleBoss, IDrawingStyle, ICompositionStyle, IHyphenationStyle, and IJustificationStyle. IPMFont and IFontInstance IPMFont encapsulates the CoolType font API. It represents a typeface and can generate instances (IFontInstance) of it at various point sizes. IPMFont is not based on IPMUnknown, but IPMFont is reference counted and can be used with InterfacePtr. For details, see the API reference documentation. IFontInstance encapsulates the CoolType font-instance API. IFontInstance represents an instance of a typeface at a given size. IFontInstance is not based on IPMUnknown, but IFontInstance is reference counted and can be used with InterfacePtr. IFontInstance controls the mapping from a character code (UTF32TextChar) into the identifier of its corresponding glyph (GlyphID). For details, see the API reference documentation. IParagraphComposer::Tiler IParagraphComposer::Tiler manages the tiles for a parcel list and is used by paragraph composers to determine the areas on a line into which text can flow (see “Tiles” on page 376). It controls the content area bounds of each line. The GetTiles method is used to get the tiles. If GetTiles cannot find large enough tiles in the current parcel that meet all the requirements, it returns kFalse and should be called again to see 382 Text Fundamentals Text composition if the next parcel in the list can meet the request. If no parcel can meet the request, the tiler returns tiles into which overset text can flow. GetTiles is a complex call to set up. To fully understand how to use it, see the API reference documentation and the text-composer samples (SingleLineComposer) provided in the SDK. The “TOP” abbreviation used in many of the parameter names is short for “top of parcel,” because when a line falls at the top of a parcel, special rules apply that govern its height (see “First-baseline offset” on page 377). For Roman composers, a tile must be wide enough to receive one glyph plus any left and right line indents that are active. A heuristic often is used that approximates the minimum glyph width to be the same as the leading. The minimum tile height depends on the metric being used to compose the line. Normally this is leading, but the first line in a parcel is a special case in which the metric used may vary depending on the first-baseline offset (ascent, cap height, and leading) associated with the parcel. The pYOffset value indicates the top of the area for text to flow into. The pYOffset value actually is a position rather than an offset from the top of the parcel. The pYOffset value initially is the yPosition stored in RecomposeHelper when the IParagraphComposer::Recompose method is called. For more details, see the API reference documentation. Scenarios This section illustrates how text gets recomposed. The scenarios presented here demonstrate basic situations you may come across in developing a paragraph composer. To reduce complexity for these examples, assume the paragraph composer being called generates only one line for each call (a single-line composer). Simple text composition Figure 179 shows a composed text frame 200 points wide and 30 points deep, with its baseline grid shown. The text is 8-point Times Regular with 10-point leading, and the first-baseline offset for the frame is set to leading. FIGURE 179 Simple text composition left = -100, top = -15 Baseline -5 5 15 right = 100, bottom = 15 When text of the same appearance is flowed into the frame, the distance between the baselines of succeeding lines of text is set to the leading. Text Fundamentals 383 Text Fundamentals Text composition The wax strand examines the paragraph attribute that specifies which paragraph composer to use and locates it through the service registry. The paragraph composer is then asked to recompose the story from the beginning, causing text to flow into the frame starting from the top by calling IParagraphComposer::Recompose(helper). The yPosition stored in the helper indicates the top of the area into which glyphs can flow. This is the baseline of the preceding line or the top of the parcel. The composer examines the drawing style and its associated font and calculates the depth and width of the tiles it needs. The example uses 8-point text with 10-point leading and no line indents, so the minimum height and width is 10 points. The tiler is then requested for tiles of the required depth and minimum width at the given yPosition, and it returns the tile shown in Figure 180. FIGURE 180 yPosition Tiles for the first line Tile for line 1 Baseline -15 -5 The following sequence of actions then occurs: 1. The paragraph composer scans the text using IComposeScanner. Text flows into the tile until the tile is full or an end-of-line character is encountered. 2. The composer chooses where the line is to be broken and creates a wax line for the range of text the line will display. 3. The wax line is applied to the IWaxStrand and, as a side effect, the composer’s IParagraphComposer::RebuildLineToFit method is called to generate wax runs for the line. 4. The IParagraphComposer::Recompose method is finished with its work and returns control to its caller. 5. The wax strand successively asks the paragraph composer to recompose the second and third lines with yPositions of -5 and 5, respectively, until the text is fully composed. The result is shown in Figure 181. For more details, see the SDK sample code SingleLineCompose. 384 Text Fundamentals Text composition FIGURE 181 Tiles for the second and third lines Tile for line 2 yPosition Baseline -5 5 Tile for line 3 5 15 Composed frame with baseline grid displayed -15 -5 -5 5 5 15 15 Change in text height on line As a line is composed, attributes that control the height of the line, like point size and leading, may change. The baseline of the text must be set to reflect the largest value of the metric, such as leading or ascent, that is being used to compose the text. To achieve this, the composer asks the tiler for tiles deep enough to take text of a given height. If an increase in text height is encountered as composition proceeds along a line, the tiler needs to be asked for deeper tiles to accommodate the text. It is the composer’s responsibility to ensure the parcel can receive the deeper text. For example, if the point size for the word “Ask” is changed to 16 points and its leading to 20 points, the text suffers change damage. The resulting sequence of recomposition is shown in Figure 182. Text Fundamentals 385 Text Fundamentals Text composition FIGURE 182 Changing point size and leading of selected text The text suffers change damage and the paragraph composer is called. yPosition Initial tile for line 2 Baseline -5 5 Leading increased. Get deeper tile. -5 15 Recomposed frame -15 -5 -5 5 5 15 15 Initially, the composer encounters 8-point text on 10-point leading, and it requests tiles of an appropriate depth. When the composer hits the style change to 16-point text and 20-point leading, it goes back to the tiler and gets a deeper tile. When the style changes back to the smaller point size, the composer already has a tile deep enough to take this text, so it fills the tile with glyphs and breaks the line. Note how the baseline is set to reflect the largest leading value encountered in the line. 386 Text Fundamentals Text composition Text wrap Depending on the yPosition and depth of the tiles needed, the text-wrap settings on other page items or a change to the shape of the frame may become significant during recomposition. To illustrate this, in Figure 183, a graphic with text wrap is added to the simple text-frame arrangement. FIGURE 183 Simple text wrap Frame Tiles Text frame with 8-point Times regular text, 10-point leading Add graphic frame with text wrap set to wrap tightly around bounding box. Figure 183 shows the text frame and the tiles the 8-point text flows into with 10-point leading. Note that the third line in the frame is affected by the text wrap and flows around the bounding box of the graphic. The following sequence illustrates what happens when the point size for “Ask” is changed to 12 points and its leading is changed to 14 points. The initial case is shown in Figure 184. FIGURE 184 Changing the selection to 12-point text, 14-point leading The wax strand picks up the change damage and asks the paragraph composer to recompose the first line of the second paragraph. The baseline of the first line of text in the frame, -5 points, is at the yPosition stored in the RecomposeHelper. The paragraph composer gets tiles deep enough to take the initial leading value (10 points) it encounters on the line, as shown in Figure 185. Text Fundamentals 387 Text Fundamentals Text composition FIGURE 185 Composer begins to recompose yPosition Baseline -5 5 The paragraph composer then encounters the run of text with the changed point size and leading. Because the text is deeper than the tiles the paragraph composer obtained, the composer goes back to the tiler and asks for a new set of tiles to receive the deeper text. This is shown in Figure 186. FIGURE 186 Composer asks for deeper tiles yPosition Baseline -5 9 Because of the request for deeper tiles and the text-wrap setting on the graphic, the tiler returns the two tiles shown in Figure 187, causing text to tightly wrap to the bounding box of the graphic. FIGURE 187 yPosition Deeper tiles Baseline -5 9 The paragraph composer flows glyphs into the deeper tiles, generating a wax line with four wax runs: one for the tile to the left of the graphic and three in the tile to the right of the graphic. After this change, all text for the story cannot be displayed in the frame, so the story is overset, as shown in Figure 188. 388 Text Fundamentals Fonts FIGURE 188 Fully recomposed frame yPosition Baseline -5 -5 9 9 It is important to note that the tiles returned by the tiler depend on the yPosition within the frame for which they are requested and the depth asked for by the caller. Frame too narrow or not deep enough IParagraphComposer::Recompose must return a wax line each time it is called; however, it is possible a frame is too narrow to accommodate text, when either the indent settings for a paragraph are large or the text has a large point size. The result is overset text. Call the tiler (IParagraphComposer::Tiler’s GetTiles()) repeatedly until it returns kTrue. The tiler iterates over all parcels; if none can accommodate the text, the tiler returns a tile into which overset text can flow. Fonts This section explains how fonts fit into the InDesign text architecture. Fonts provide the basic information required to render glyphs. A font is identified by a font name (e.g., “Minion Pro”) and a face or style name (e.g., “Bold” or “Heavy”). A rendered font also has a size; for example, this text is 11 pt (points). The font, along with the point size, is an instance of the font. All rendered text in the application has an associated font. The operating system provides a set of font services, though fonts unique to the application can be maintained in the application fonts folder. An application installation has a set of fonts available (from either the operating system or the application fonts folder). The font manager provides these fonts to the user while the document is being edited. There are times when the font manager gets a request for a font that is not available; for example, the font was removed from the system or the document was produced on a system with a different set of available fonts. The font manager resolves this situation by replacing the font with one that is available. The font manager warns the user when such a replacement occurs. Fonts have rights, which determine what can be done with a particular font. For example, a font can indicate that it should not be embedded in a PDF document or it should not be printed. The font subsystem provides access to these rights and implements the policies required to adhere to these rights. Text Fundamentals 389 Text Fundamentals Fonts Font management within the application relies on a core piece of Adobe technology, CoolType. CoolType wraps the operating-system font services to provide a cross-platform abstraction and provides further services to clients. Font-subsystem architecture The application wraps the CoolType representation of fonts, font groups, and font instances with application-specific types. This is shown in Figure 189. FIGURE 189 Accessing CoolType fonts in the application kSessionBoss IFontMgr «interface» IFontMgr 1 1 QueryFont 1 QueryFontGroup * * IPMFont * IFontGroup IFontInstance GetCTFontDict CoolType font sybsystem CTFontDict 390 GetCTFontGroup CTFontGroup GetCTFontInst CTFontInstance InDesign wrappers for core CoolType types. Interfaces do not inherit from IPMUnknown. QueryFontInstance OS font subsystem Text Fundamentals Fonts IFontMgr on kSession provides access to the CoolType font wrappers. IPMFont is the representation of a font, IFontGroup represents a group of related fonts, and IFontInstance represents a particular font at a particular point size. Font manager The font manager provides access to all font groups available to the application. Each font group allows you to access each font in the group. The IFontMgr interface is aggregated on kSessionBoss. CoolType CoolType is the core technology through which an application can access fonts. It automatically loads the fonts made available by the operating system. In addition, CoolType can load fonts directly from the common Adobe fonts folder and the Fonts folder inside the application’s folder. The API provides the IFontGroup, IPMFont, and IFontInstance interfaces as shells through which the application calls CoolType. These are not standard interfaces; that is, they do not derive from IPMUnknown. You cannot create them using CreateObject or query them for other interfaces; however, these interfaces are reference counted, and you can manage their lifetime using InterfacePtr. See Table 96 and Figure 190. TABLE 96 Interfaces that use CoolType Interface Description How to get the interface Code snippet with example of use IFontGroup Represents all font groups available to the application IFontMgr::QueryFontGroup, FontGroupIteratorCallBack SnpPerformFontGroupIterat or IPMFont Provides extensive data related to a particular font. IPMFont provides font-name mapping calls and access to font metrics at a given point size. IFontMgr::QueryFont, IFontMgr::QueryFontPlatform, IFontFamily, text attributes kTextAttrFontUIDBoss and kTextAttrFontStyleBoss, IStoryService, IWaxRenderData SnpInspectFontMgr IFontInstance Represents an instance of a font of a given point size. Of interest if you need to write a paragraph composer or map character codes to GlyphIDs. IFontMgr, IDrawingStyle, IStoryService SnpInsertGlyph Text Fundamentals 391 Text Fundamentals Fonts FIGURE 190 Accessing a font QueryFont kComposeStyleBoss IPMFont IDrawingStyle QueryFontInstance IFontInstance Fonts are used when composing text, as fonts define the characteristics of individual glyphs. kComposeStyleBoss is used by the composition engine. The IDrawingStyle interface provides access to the font (IPMFont) and particular instance (IFontInstance) being used Fonts within the document Within a document, fonts are represented by the font name (plus information on font style and point size). When the actual font is required, the font manager resolves the name-to-font (IPMFont or IFontInstance) mapping. The document-font manager The document-font manager (IDocFontMgr) provides access to all fonts that persist in a session or document workspace. The fonts that exist in a document include a set of default fonts, fonts used in visible stories, and fonts used for features that are modeled using the application text subsystem but not intended to be viewed or printed as part of a story (for example, text that exists in notes). Fonts in the persistent document Fonts are represented in the object model by kFontGroupBoss (signature interface IFontFamily). Each font used in a story results in an instance of this boss object. A font family along with a font style identifies a particular font in the font subsystem. The font family represents the name of the font (more correctly, the set of names that identify each font within a particular group). This decoupling between font and name in the document allows the font manager to resolve the font when required and take appropriate measures if the font is not available to the application. The relationship between font manager and fonts is shown in Figure 191 392 Text Fundamentals Fonts FIGURE 191 How fonts persist in a document IDocFontMgr exists on the session or document workspace. The set of default fonts inherited by new documents is maintained in IDocFontMg r on the session workspace. The set of fonts used by a document is maintained on the document workspace. «interface» IDocFontMgr Note that the fonts used by visible text in all stories are ident ified by IDocFontMgr. Fonts used in placed assets (EPS or PDF) and fonts used in non-visible text in stories (such as with notes) are not maint ained on IDocFontMgr. 1 GetNthFontGroupUID m..* kFontGroupBoss IFontFamily «interface» «interface» IFontFamily + IPMFont QueryFace FontName: PMString 1 1..* A font persists as a name, contained within a persistent implementation of IFontFamily. Access to these persistent objects is provided through the (session or document) workspace. IFontFamily::QueryFace requests the font from the font manager. If the returned IPMFont is nonnil, IPMFont::FontStatus can be used to determine the validity of the font. A set of text within a story is associated with a particular font using standard text attributes. The text attributes that refer to the font in which text appears are as follows: z kTextAttrFontUIDBoss — ITextAttrUID gives the UID of the font family. z kTextAttrFontStyleBoss — ITextAttrFont gives the name of the stylistic variant. z kTextAttrPointSizeBoss — ITextAttrRealNumber gives the point size used. The font family, along with the style of the font, identifies a particular font (IPMFont). The point size of the text is used to provide an instance of the font (IFontInstance). Text attributes are introduced and described fully in “Text formatting” on page 324. The used-font list The used-font list (IUsedFontList) on a document (kDocBoss) details the fonts associated with story text. The used-font list does not include the fonts used in features that are not intended to be viewed or printed as part of a story (for example, text that exists in notes). Text Fundamentals 393 Text Fundamentals Fonts Fonts in placed assets Placed (EPS or PDF) assets support the IFontNames interface. This interface reports the fonts used for the particular asset, including whether the asset depends on the presence of fonts on the system. Placed assets are maintained in the native asset’s format (PDF or EPS), with the IFontNames interface providing access to information within the asset. Document font use A utility interface (IDocumentFontUsage) on the document (kDocBoss) provides a facade over the two interfaces introduced above (IUsedFontList and IFontNames). Font naming Internally, application code uses PostScript font names. For example, IPMFont::AppendFontName returns the PostScript font name. If you know the PostScript name of the font you want, you can get the associated IPMFont using IFontMgr::QueryFont. Several other names are available on IPMFont and IFontFamily. For example, if you use IFontMgr::QueryFont to instantiate the PostScript font AGaramond-Italic, IPMFont gives you the names shown in the table in Figure 192. FIGURE 192 Font names Name 394 Method Example PostScript font name IPMFont::AppendFontName AGaramond-Italic Family name IPMFont::AppendFamilyName Adobe Garamond Style name IPMFont::AppendStyleName Italic IPMFont::AppendFullName Adobe Garamond Italic IPMFont::AppendFamilyNameNative Adobe Garamond IPMFont::AppendStyleNameNative Italic IPMFont::AppendFullNameNative Adobe Garamond Italic Text Fundamentals Fonts Notice the typeface name Adobe Garamond Pro in the panel in Figure 192 does not match the family name in the table. This is because ITextUtils::GetDisplayFontNames supplies the platform-specific name in the Character panel. If you do not have the PostScript font name but know the name of the typeface on a given platform (the typeface name in Windows or the family name in Mac OS), IFontMgr::QueryFontPlatform returns the corresponding IPMFont. Font warnings The IDocumentFontUsage interface (on kDocBoss) manages used-font and missing-font information for text in stories of a document. The IDocumentFontUsage interface does not detail fonts used by features that rely on the application text model but are not rendered as part of the document (for example, notes). The IMissingFontSignalData interface provides data sent with the missing-font signal (of which responders of type kMissingFontSignalResponderService are notified). The IFontUseWarningManager interface can be called to check a particular font and possibly warn the user about restrictions. Examples are restrictions based on user preferences or because a font is a bitmap. Composite fonts and international-font issues Some languages too many glyphs to be contained in a font; for example, Japanese contains about 50,000. To accommodate this, font developers create fonts with subsets of glyphs. Also, there is a desire within typography to replace some glyphs with others to achieve a certain visual effect. And users might want to shift the position of Roman glyphs relative to the baseline or enlarge or reduce the size of glyphs. See Figure 193. FIGURE 193 Japanese and Roman typography metrics Japanese Roman Em-box top Ascent ICF box top Em-box center Baseline ICF box bottom Em-box bottom Descent The ICompositeFont interface creates a new font composed of base fonts and provides for size and positioning adjustments. Font switching is based on Unicode values. The base font must be a Chinese, Japanese, or Korean font. For examples of using ICompositeFont, see the SnpPerformCompFont code snippet. An application can get this interface using any of the following: z IStyleNameTable (from the active workspace or document workspace) z InterfacePtr<IStyleNameTable> compFontList(workspace, IID_ICOMPOSITEFONTLIST) z InterfacePtr<ICompositeFont> rootTable(docDatabase, StyleUID(), IID_ICOMPOSITEFONT) Text Fundamentals compFontList-> GetRoot- 395 Text Fundamentals Fonts Use the ICompositeFontMgr interface to manage composite fonts. For examples of its use, see the SDK code snippet SnpPerformCompFont. The IFontMetricsTable interface obtains the correct tsume values (similar to side bearings on glyphs) around either the top and bottom or left and right of glyphs from the document originator and caches them. Later users (who might have only bitmaps of the fonts used to create the document) can use the tsume metrics saved in the document through this interface. 396 Tables Concepts Tables This chapter describes concepts and architecture related to the table feature of InDesign. Table attributes are boss classes with ITableAttrReport implementation; they are discussed in “Table attributes” on page 407. Table and cell styles define a collection of table attributes that are appropriate for tables or cells. They can be applied to individual tables and cells. See “Table and cell styles” on page 409. For information on how to work with table models and APIs, see the “Tables” chapter of Adobe InDesign CS4 Solutions. Concepts Table structure Tables in InDesign publications consist of rows, columns, and cells. Cells can span multiple rows or columns, as in the HTML 4 table model, which evolved from the CALS SGML table model. There are helper classes in the InDesign API that are used to specify location, dimension of cells, and areas within tables. The abstractions used to specify these are shown in Figure 194. For this example, the resolution of the underlying grid is 4 (rows) by 3 (columns). Cells can consist of merged elements on this underlying grid. FIGURE 194 Table-structure example GridAddress(0,0) GridSpan(1,3) GridAddress(1,0) GridSpan(1,3) GridAddress(2,0) GridSpan (1,2) GridAddress(2,2) GridSpan(1,1) GridAddress (3,0) GridAddress(3,1) GridAddress(3,2) GridSpan(1,1) GridSpan(1,1) GridSpan(1,1) Whole table: GridArea(0,0,4,3) Tables 397 Tables Concepts Anchor cells versus grid elements The top-left of a cell is its anchor. A grid element is a unit on the underlying grid. Grid elements may or may not be anchor cells. A cell can comprise multiple elements on the underlying grid, but there is at most one anchor point per cell. To access the text content of a cell, some API methods require a GridAddress that refers to an anchor, whereas other methods can work with a grid element that is not necessarily an anchor. GridAddress The API helper class GridAddress identifies the location of cells within tables. GridAddress and the other GridXXX classes are defined in TableTypes.h. In InDesign, GridCoord is an alias for the primitive type int32. The non-default constructor for GridAddress is as follows: GridAddress(GridCoord row, GridCoord column) where row and column are the row and column, respectively, in which the top-left of the cell is located. Another key concept is the underlying grid on which measurements are made, consisting of grid elements. For example, if a cell is split by a vertical line, this increases the resolution of the grid in the horizontal direction. The resolution of the grid in a given direction is determined by projecting all cell boundaries onto an axis in that direction. Adding another vertical line means an additional projection onto the horizontal axis; i.e., an increase in horizontal grid resolution. The grid lines are not uniformly distributed. The grid is rectilinear. Determining what row a particular cell is in can become quite complex in a table with many split and merged cells; that is, tables with many nontrivial GridSpan values. The algorithm to determine the GridAddress for a particular cell is straightforward: 1. Determine the resolution of the underlying grid. For the horizontal direction, this can be calculated by projecting all vertical edges to the x-axis (top of the table). Similarly, for the vertical direction, project all horizontal edges to the y-axis (left of the table). 2. Calculate the coordinates on this grid. The process is shown in Figure 195. The underlying grid is just fine enough so there are no cell edges that do not lie on an edge in this underlying grid. In the figure, the GridAddress of the red cell is (8, 9). The table has an underlying grid 12 rows wide and 11 columns high. 398 Tables Concepts FIGURE 195 0 Complex table and underlying grid 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8,9 The GridAddress of a cell can change even if its physical location does not change. GridSpan GridSpan is a class that represents the dimension of an area within a table, expressed as coverage of elements in the notional underlying grid. GridSpan has a constructor with two arguments: GridSpan(int32 height, int32 width) where height and columns are the numbers of rows and columns spanned, respectively (on the underlying grid). When a table is created (e.g., using the Insert Table menu command), each cell in the table has the trivial GridSpan(1,1). The concept of GridSpan is illustrated in Figure 194, which shows the GridSpan for several cell configurations The GridSpan of a given cell can change as more cells are added to a table—for example, by a cell being split vertically in a column that this cell spans—even if the physical dimension of the cell of interest does not vary. GridSpan for a cell is affected by changes in the columns spanned by a cell and the rows spanned by a cell. Merging a pair of cells with trivial GridSpan(1,1) gives one cell with a GridSpan(2,1) if the cells are merged vertically and GridSpan(1,2) if the cells are merged horizontally. Cells may be unmerged by selecting any merged cells—even the whole table—and choosing Unmerge Cells. Splitting a cell with GridSpan(2,1) in the vertical direction gives two cells with trivial GridSpan(1,1). Splitting the cell horizontally leads to the GridSpan of other cells in the table being recalculated. Tables 399 Tables Concepts GridArea The GridArea class is used to specify a region within a table. Like GridSpan and GridAddress, GridArea is calculated on the underlying grid. GridArea has a constructor with four arguments: GridArea(GridCoord topRow, GridCoord leftColumn, GridCoord bottomRow, GridCoord rightColumn) where: z topRow is the row coordinate for the top-left of area. z leftColumn is the column coordinate for the top-left of area. z bottomRow is one greater than the lowest row contained in the area; i.e., the row immediately below the given area and outside it. z rightColumn is one greater than the rightmost column contained in this area; i.e., the column immediately to the right of the given area and outside it. The choice of using one greater than the last row or column allows for specifying an empty area in a simple way. That is, an empty GridArea can be specified by writing GridArea(0,0,0,0), for example. Alternately, given the definition of GridArea, it is equivalent to the following: GridArea(top, left, row-span, column-span) Table and cell selection You can select a whole table or cells within a table, allowing the selected cells to be deleted or their properties to be altered as a block. Alternately, you can select text within a table cell, allowing the text properties to be specified for this text run. This is shown in Figure 196 and Figure 197. FIGURE 196 400 Table cells selected Tables Concepts FIGURE 197 Table text selected The selection manager hides the detail of the particular selection type involved from client code. The intent is that client code interact with the table model only indirectly, through the integrator suite interfaces, which present a uniform facade to client code. When the cursor is within a table cell, InDesign can perform operations for any of the three selection types: text selection, cell selection, and table selection. Some operations are possible only with table cells selected; for example, the Merge Cells command is enabled only when multiple table cells are selected. Table composition Typically, a table is associated with a text frame. One text frame can contain multiple tables. The table composer flows the row content of tables between table frames. Once a table becomes too deep for the containing text frame, rows from the table may be flowed to another text frame, if there is one linked to the current table’s text frame. Only whole rows are flowed by the table composer. Text composition within a table cell uses the same text-composition engines that operates over normal text (i.e., text outside tables). For more information on text composition, see the “Text Fundamentals” chapter. A text frame that contains one or more table rows that are too deep to display is marked as overset. The overset rows can be flowed to another text frame by linking the frames, exactly as for overset text. The visual indicator for table cell overset is drawn as a text adornment. Tables can be wider than the containing text frame; table rows, on the other hand, flow between linked cells, or the frame is marked as overset. Tables 401 Tables Design and architecture Table region A table can be viewed as composed of regions: header rows, footer rows, left column, right column, and body rows. When inserting a table, headers and footers can be specified in the Insert Table dialog box. A table style can set different cell styles for each region. Design and architecture Table model versus text model Text-model extensions for tables The basic text model API is extended to accommodate tables. kTextStoryBoss aggregates interfaces to support the abstraction of text-story threads, which are spans of characters that represent the text content of one cell. The text-story thread interface (ITextStoryThread) is aggregated on the kTextStoryBoss class, which is used to represent the main text flow within a story designated as the primary story thread. Many higher-level APIs make it possible to manipulate the content of text cells without having to manipulate the underlying text model directly. The essential API for this is the ITableTextContent interface, which is aggregated on the kTableModelBoss class. This provides a mechanism to get and set table text in chunks. How tables are connected to text The kTextStoryBoss boss class is the fundamental class that represents the textual content of stories. For more information, see the “Text Fundamentals” chapter. A story can contain zero or more tables. Tables can be nested within tables to an arbitrary depth. The text-model interface (ITextModel) is the fundamental API to interact with stories; for every table, there is an embedding story. An ITextModel interface can be used to obtain the text-cell contents. The UML diagram in Figure 198 is a graphical representation of the relationship between the story and table models. It shows other key abstractions, such as the tablemodel list and the TextStoryThreadDictHier. 402 Tables Design and architecture FIGURE 198 Relation between story and table models KTextStoryBoss 1 1 1 1 1 text::ITextStoryThreadDictHier table::ITableModelList Manages collection Manages collection text::ITextStoryThreadDict table::ITableModel 1 1 1 1 kTableModelBoss 1 Text and tables are connected in two ways: z Through the table-model list (ITableModelList, aggregated on kTextStoryBoss). This is relatively straightforward to understand, but it may be deprecated in future versions of the API. z Through ITextStoryThreadDictHier. This is more complex to understand, but it represents the new architecture and will be a more dependable API moving forward. Obtaining a reference to ITableModel through the table model list meant making a series of API calls by client code to navigate the table architecture. The alternative scheme to obtain a reference to an ITableModel has a starting point of an ITextModel interface on a kTextStoryBoss object. The difference is that there is no dependence on ITableModelList. Another API that allows connections between tables and text to be explored is ITableTextContainer. Given a table, ITableTextContainer allows client code to determine the embedding text model. This interface is aggregated on kTableModelBoss. Tables 403 Tables Design and architecture Table data model A key abstraction in the table model is the kTableModelBoss boss class. Among other things, this class encapsulates the data model for a table, allows iteration over the cells in a table, allows access and modification of the attributes of a table, and provides access to the text chunks (or other content) in a table. It provides APIs that enable copy, paste, and deletion of content and access to the geometry of the table. For some of the key interfaces aggregated on the boss class, see Figure 199. FIGURE 199 Interfaces on the kTableModelBoss boss class Access to text in cells Information about text flow in which table is anchored <<interface>> ITableTextContent <<interface>> ITableTextContainer <<interface>> ITableGeometry <<interface>> ITableLayout ITableCommands encapsulates change to the model in a command sequence and provides undo/redo services to client code. kTableModelBoss <<interface>> ITableCommands <<use> <<use> <<use> <<interface>> ITableModel <<interface>> ITableAttrAccessor Read-only access to the geometry ITableLayout is responsible for mapping the model to the composed state. <<interface>> ITableAttrModifier Core of the table model subsystem; table structure, copy/paste, content boss, and text content manager access NOTE: Plug-in (client) code that uses the API exposed through interfaces aggregated on the kTableModelBoss class should be written to use the selection suites and facades. The kTableModelBoss boss class aggregates interfaces like ITableModel. This interface has methods to obtain table iterators; these can be used to navigate a table or iterate through a specific GridArea within a table. These are STL-like iterators, supporting both forward and reverse iteration. The ITableAttrAccessor and ITableAttrModifier interfaces also are aggregated on kTableModelBoss. These provide detailed queries over the set of table attributes and allow applying overrides to table and cell attributes. In practice, most of the capability required for client code to 404 Tables Design and architecture query attributes and apply overrides is provided by the more convenient suite interface, ITableSuite. ITableAttrModifier is not likely to be used directly by client code; all the capabilities exposed by this interface are available through methods on ITableCommands, which wrap changes to the document object model in a command sequence in a clean and convenient way for client code to use. Client code should use ITableCommands (rather than ITableAttrModifier). See the API Reference for details of the interfaces aggregated on kTableModelBoss. The ITableTextContent interface is aggregated on kTableModelBoss; this allows the text contained within cells to be accessed. Do not confuse this interface with ITableTextContainer, which is a fundamental API that represents the connection between a table and the story (kTextStoryBoss) within which it is embedded. The kTableModelBoss class represents the data model for an entire table. A table is composed into a set of table frames (kTableFrameBoss) by the table composer. <SDK>/source/sdksamples/tablebasics indicates how to acquire a reference to a table model. This code is in the context of a suite implementation that was added to a concrete-selection boss class. Table layout ITableLayout on kTableModelBoss provides detailed information about the layout of the table. ITableLayout centralizes the persistent data into one implementation and contains several subclasses responsible for maintaining table layout information, like Row (representing the composed state of table-model rows), Frame (mapped to one persistent kTableFrameBoss object), and Parcel (holding information about IParcel). ITableLayout also provides iterators to access these layout elements. For example, ITableFrame can be obtained from ITableLayout using the following snippet: // Assume that iTableModel is a valid table model interface ptr. InterfacePtr<ITableLayout> tableLayout(iTableModel , UseDefaultIID()); ITableLayout::frame_iterator frameIter = tableLayout->begin_frame_iterator(); ITableLayout::frame_iterator endFrameIter = tableLayout->end_frame_iterator(); while(frameIter != endFrameIter) { InterfacePtr<ITableFrame> tableFrame(frameIter->QueryFrame()); ... } The ITableLayout::Row subclass represents the partial mapping of a model row to a table frame (represented by the kTableFrameBoss). For each model row, there is one or more corresponding table layout rows. Each row contains information for each parcel owned by a table cell, like the GridCoord of the model row it maps and the UID of the table frame with which it is associated. Each layout row is associated with one table frame. ITableLayout is responsible for the lifetime management of table frames. Besides containing the layout rows, the table frame also is responsible for maintaining the link back to the containing Parcel and associated ParcelList. Tables 405 Tables Design and architecture Table frames The rows in a table may not all fit in one text frame. The table composer groups as many rows as will fit into the first text frame, the second text frame, and so on. A table with many rows may be spread across multiple, linked, text frames. These groups of rows are table frames. Each row is part of one and only one table frame. A table is divided into one or more table frames, spread across one or more text frames. A table frame (represented by the kTableFrameBoss boss class) is a collection of rows within a text frame. There can be multiple table frames within a text frame (if the text frame contains multiple tables), so there are at least as many table frames as text frames. An occurrence of a table frame leads to its UID for the corresponding kTableFrameBoss object appearing in the owned item strand. Tables can have an arbitrary number of table frames, split between linked text frames. If rows cannot be displayed within the last linked frame in the series, the frame is marked as overset. For each text frame, there is a corresponding table frame that represents the collection of rows being displayed within the given text frame. For each row of a table, there is an occurrence of the kTextChar_Table or kTextChar_TableContinued character in the text data strand. For more information, see the “Text Fundamentals” chapter. Cell data model Cell-content managers The table architecture supports having different cell-content managers. In practice, InDesign has only text cell-content manager (with behavior provided by kTextCellContentMgrBoss) and a dummy cell-content manager. (Future versions of InDesign may add canonical cell-content managers for content types like images.) You may add your own types of cell-content managers. The main responsibility of a cell-content manager is to implement the ICellContentMgr interface. A cell-content manager is created during table creation. You can get the cell-content manager from the table via ITableModel::QueryContentMgr(). Cell contents Text cells (the only kind in InDesign) have behavior provided by the kTextCellContentBoss boss class. Instances of this boss class do not store the content directly but provide a convenient API on top of the table text model to allow its manipulation. It also is possible to quickly and conveniently manipulate the text content of a cell through the text model. In this case, API classes like TextIterator can be used to access a range within the text model. To set cell text, the ITableCommands::SetCellText API method makes it straightforward to change the cell text at a given GridAddress. The ITableCommands interface is aggregated on kTableModelBoss. 406 Tables Design and architecture Code snippets like SnpAccessTableContent.cpp show how to work with the APIs to access cell contents. See also the TableBasics plug-in and the SnpSortTable.cpp code snippet for examples of accessing and manipulating table text content. Cell strands The kCellStrandBoss cell strand provides storage for cell attributes and aggregates an ITableStrand interface. This abstraction is likely to be hidden from client code and should be treated as an implementation feature. Higher-level APIs, like ITableAttrAccessor and ITableCommands, provide methods to access and modify attributes without having to work at the lower level of representation of the table strand. Table attributes The table architecture supports extensible attributes with inheritance. Attributes can be applied to an entire table or one or more cells within a table, and there also are a small set of row-specific and column-specific attributes. As with the text subsystem, attributes are represented by boss classes. Table-attribute boss classes have names that follow the pattern k<targetentity>Attr<property>Boss, where <target-entity> is one of Table, Cell, Row, or Column. Some text-cell-specific attributes have TextCell in the attribute name. The ITableAttrReport::AppendDescription method reports whether an attribute is a cell-specific, row-specific, column-specific, or table-specific attribute. To obtain information about the default value of each attribute, see the API reference documentation. Table-specific attributes A table attribute describes one property of an entire table. A table attribute is applied to the table itself; the attributes collectively define aspects of how the table should appear. A table attribute is represented by a table attribute boss with a name that conforms to the pattern kTableAttr<property>Boss. Row attributes There are only a few row-specific attributes, which apply to a row or collection of rows within the table. Row attributes are represented by boss classes. For details, see kRowAttrBaseBoss in the API reference documentation. These are named to follow the pattern kRowAttr<property>Boss. Column attributes There are very few column-specific attributes. For details, see kColAttrBaseBoss in the API reference documentation. These are represented by boss classes, which are named to follow the pattern kColAttr<property>Boss. Tables 407 Tables Design and architecture Cell-specific attributes There are a wide range of cell-specific attributes that can be overridden. These can be divided into those that apply to an entire cell and those that are specific to one border (bottom, left, right, top) of the cell. See Figure 200. FIGURE 200 Examples of cell-specific attributes This cell has an override (2p) for the bottom text inset kCellAttrBottomInsetBoss This cell has an override for the bottom stroke color kCellAttrBottomStrokeColorBoss This cell has an override for the bottom tint kCellAttrBottomStrokeTintBoss This cell has an override for the cell fill color This cell has an override for a diagonal tint kCellAttrFillColorBoss kCellAttrDiagnolTintBoss This is a cell that has had its first line offset set to be fixed and with contents clipped to cell kCellAttrClipBoss This is a cell that has had its first line offset set to be fixed but without contents clipped to cell kCellAttrClipBoss This cell has an inline graphic and some This cell has an inline graphic and some text that flows around it. It has a diagonal in front of the cell contents text that flows around it. It has a diagonal behind the cell contents kCellAttrDiagnolsOnTopBoss kCellAttrDiagnolsOnTopBoss . 408 kCellAttrRotationBoss This cell has an override for the rotation (90 deg.) kCellAttrRotationBoss This cell has an override for the rotation (270 deg.) This cell has an override (4 pt) for the bottom stroke This cell has no overrides. weight kCellAttrBottomStrokeWeightBoss Tables Design and architecture Text-cell-specific attributes Some cell attributes apply only to text cells. Text cells are the only supported kind of cell in InDesign, but future versions may support other cell-content types, so text cells are not generic-cell attributes. Text-cell attributes are represented by boss classes named to follow the pattern kTextCellAttr<property>Boss. Default table attributes The ITableAttributes interface is aggregated on the workspace (kWorkspaceBoss class) and the document workspace (kDocWorkspaceBoss class), with interface identifier IID_IDEFAULTTABLEATTRIBUTES. When a new document is created, this root set of table attributes is applied to the document. This attribute list is further enhanced when the swatch list is available for the new document, since some of the attributes reference a swatch (black or none) by UID. When a new table is created (by kNewTableCmdBoss class, an instance of which is created and executed through the ITableCommands interface on kTableModelBoss), the root table style is applied to the table. Table and cell styles A style can be considered a collection of attributes. Table and cell styles provide a mechanism to name and persist a particular set of table attributes. Table style and cell style are analogous to paragraph style and character style in the text. Each style has an AttributeBossList list that maintains the set of attributes that apply to that style. Access to the attributes in a style is achieved through the ITableAttributes interface. Cell styles are associated with cell-specific attributes; however, table styles can be associated with both table attributes and cell-specific and other attributes. Styles form a hierarchy rooted at the root style. Each style (except the root style) is based on a style. The AttributeBossList list for a particular style records only the differences from the style on which it is based; that is, the set of attributes the particular style overrides. As with other types of styles, table and cell styles support the Style Group concept. Users can create, edit and delete folders (called Groups), in the table styles and cell styles palettes. Style group is a collection of styles or groups. The user also can nest groups inside groups and drag styles within the palette to edit the contents of a group. Styles do not need to be inside a group and can exist at the root level of the palette. Table styles A table style is represented by a kTableStyleBoss. Its IStyleInfo stores general, style-related information like style name and parent style. Its ITableAttributes interface stores a list of table attributes that are different from its parent. The root table style (known in the application user interface as [No Table Style]) contains a complete set of default table attributes. This defines the default look of the table with no further formatting applied. Tables 409 Tables Design and architecture The application also defines a basic table style called [Basic Table]. The basic style cannot be deleted, but you can change it. Initially, the basic style is based on the root style; however, its parent style can be changed. Table styles are accessible through the table-style group manager (signature interface IStyleGroupManager with interface identifier IID_ITABLESTYLEGROUPMANAGER) on the document (kDocWorkspaceBoss) and session (kWorkspaceBoss) workspace boss classes. When a document is created, its style group manager inherits the existing set of styles from the session workspace. THe IStyleGroupManager of the table styles works exactly the same way as that of paragraph and character styles. For details, see the “Text Fundamentals” chapter. Cell styles A cell style is represented by a kCellStyleBoss. Its IStyleInfo store general, style-related information like style name and parent style. Its ITableAttributes interface (with implementation kCellStyleCellAttributeListImpl) stores a list of cell-specific attributes that are different from its parent cell style. The root cell style (known in the application user interface as [None]) is really nothing; in fact, it defines nothing. It is synonymous with the root character style. The root cell style cannot be deleted. Cell styles are accessible through the cell-style group manager (signature interface IStyleGroupManager with interface identifier IID_ICELLSTYLEGROUPMANAGER) on the document (kDocWorkspaceBoss) and session (kWorkspaceBoss) workspace boss classes. When a document is created, its style group manager inherits the existing set of styles from the session workspace. As with table styles, the IStyleGroupManager of the cell styles works the same way as that of paragraph and character styles. For details, see the “Text Fundamentals” chapter. Regional cell styles Each table style can assign different cell styles for different regions: headers rows, footers rows, first column, last column, and body rows. When a table style is applied to a table, these regional cell styles are applied to the appropriate regions. Regional cell styles are considered as table attributes of a table style. Except for body rows, the values of two related attributes, “cell style” and “use body,” determine a regional style. See Table 97. 410 Tables Design and architecture TABLE 97 Regions and their controlling attributes Region Cell-style attribute boss Use body attribute boss Body rows kTableAttrBodyCellStyleBoss kInvalidClass Header rows kTableAttrHeaderCellStyleBoss kTableAttrHeaderUseBodyCellStyleBoss Footer rows kTableAttrFooterCellStyleBoss kTableAttrFooterUseBodyCellStyleBoss Left column kTableAttrLeftColCellStyleBoss kTableAttrLeftColUseBodyCellStyleBoss Right column kTableAttrRightColCellStyleBoss kTableAttrRightColUseBodyCellStyleBoss To set a regional cell style, you need to create and apply an appropriate “cell style” attribute as well as create and apply an appropriate “use body” attribute (except for body rows). To get a regional cell style, you need to look for these attributes at the complete list of attributes. For more information, see the “Tables” chapter of Adobe InDesign CS4 Solutions. Table and cell style in the data model Figure 201 illustrates a simplified class diagram of table styles, cell styles, and their relationships to application/document workspaces and the table model. The descriptions of the boss classes give hints to navigate through these related classes. Tables 411 Tables Design and architecture FIGURE 201 Table and cell style The table. Table's own ITableAttributes stores local overrides of table attribute. The application or document preferences. The workspace stores table styles and cell styles. They are accessible through IStyleGroupManager interface using interface identifier IID_ITABLESTYLEGROUPMANAGER and IID_ITABLESTYLEGROUPMANAGER respectviely. It's ITableAttrModifier interface has access to the table style applied. Its ITableAttrAccess encapsulate the access to applied cell style for individual cell. Represents individual cell. Its ITableStrand stores cell attribute overrides. «boss» kWorkspaceBoss kDocWorkspaceBoss ITableModelStorage::QueryNthStrand() 1 1 «boss» kTableModelBoss ITableAttributes 1 1 1 ITableAttrAccessor::GetCellStyle ITableAttrModifier::GetTableStyle() 1..* IStyleGroupManager::FindByName() «boss» kCellStrandBoss 1 1..* «struct» ITableAttributes::QueryByClassID() kTableStyleBoss 1 1..* IStyleGroupManager::FindByName() 1..* «struct» kCellStyleBoss ITableAttributes 1..* The table style. It can define different cell style for different region. They are defined as attributes of the table style, thus need to query appropriate Boss class to get the regional style. 412 The cell style. Its ITableAttribute interface stores the cell specific attribute of the cell style, includes the default paragraph style. ITableStrand Tables Design and architecture Formatting tables, cells, and table text Formatting a table Tables are formatted according to table-specific attributes. Every table is assigned a table style. ITableAttributes, aggregated on kTableModelBoss, provides coarse-grained access to the locally overridden attribute list for a particular table. For a given attribute (such as table stroke), InDesign follows these steps to format a table: 1. If there is a local override, format the table according to the override. 2. Otherwise, check the attributes in the table style of the table. If the attribute is among those attributes defined in ITableAttributes of kTableStyleBoss, format the table according to the value of the attribute defined in the table style. 3. Otherwise, check the table style’s parent style, until either the attribute is found or the root table style (which defines all default attributes) is reached. Format the table according the value of the attribute. Formatting a cell Cells are formatted according to cell-specific attributes, similar to tables. For a given cell attribute, InDesign follows these steps to format a cell: 1. If there is a local override, format the cell according to the override (which is defined in ITableStrand on kCellStrandBoss). 2. Otherwise, check the attribute against the attribute list of the cell style applied to the cell. To determine the cell style, check if a cell-style override is applied. If so, use the cell style; otherwise, use the regional cell style defined in the table style of the table. 3. As with table styles, if the attribute is among the attributes defined in ITableAttributes of kCellStyleBoss, format the cell according to the value of the attribute defined in the cell style. Otherwise, check the cell style’s parent style, until either the attribute is found or the root cell style (where nothing is defined) is reached. Format the cell according to the value of the attribute or leave it as the default format. Formatting text in a cell It is helpful to view table attributes as equivalent to paragraph-level attributes for normal text, and cell attributes as equivalent to character-level attributes. The analogy holds insofar as the effective attributes are calculated by applying the following in the order listed below: Tables z Table-style attributes z Table-level overrides z Row or column cell style z Cell overrides z The paragraph style defined by the cell z Paragraph override 413 Tables Essential APIs z Character style z Character overrides To format a character in a table cell, InDesign looks at the reverse of the order above. An override always takes priority than a style; a smaller range style always takes priority over a coarse one. TABLE 98 Text-formatting priorities Overrides Styles Character overrides Character styles Paragraph overrides Paragraph styles Cell overrides Cell style Table overrides Table style A cell style can have a paragraph style used in the paragraphs of a cell to which the cell style is applied. If a cell style does not have a paragraph style defined, any cell that has that cell style applied to it will have all paragraph-style formatting removed. Essential APIs Table commands ITableCommands is an interface that is aggregated by kTableModelBoss and provides methods to create and execute table-related commands, instead of having to manipulate the table model at a lower level. You can use ITableCommands to affect the table model on any specific table area. Some functions in ITableCommands also are provided by ITableSuite, which instead operates on the currently selected area of the table. For more details, see ITableCommands in the API reference documentation. ITableSuite ITableSuite is a key API for manipulating tables in client code. It provides much of the required capability for plug-ins, with the exception of insertion and retrieval of cell content. The ITableSuite interface is aggregated on the integrator suite boss class (kIntegratorSuiteBoss), which makes it available through the abstract selection. Implementations of this interface are provided on various concrete-selection boss classes, which are hidden from client code through the facade of the abstract selection. To obtain ITableSuite, client code should query the selection manager (ISelectionManager) for the interface. 414 Tables Essential APIs The integrator suites expose methods that determine whether a capability is present on the current selection; this always should be tested before trying to exercise a capability. For more detail on the integrator suites, see the “Selection” chapter. Suite interfaces typically use this pattern of checking for a service (capability) and, if the abstract selection supports the capability, calling the method called. For details, see ITableSuite in the API reference documentation. Use is illustrated in the following code: bool16 canDeleteTable = iTableSuite->CanDeleteTable(); if(canDeleteTable) { iTableSuite->DeleteTable(); } ITableStyleSuite and ITableStylesFacade ITableStyleSuite is the selection suite used to manipulate table styles, such as creating and editing table styles of a selected table; applying a table style to the current selection; and getting and setting local overrides of table attributes. As with other selection suites, the interface can be acquired through ISelectionManager. Aggregated on kUtilsBoss, ITablesStylesFacade is used to manipulate table styles on a table or table style directly. It is the counterpart of ITableStyleSuite. The ITableAttrAccessor and ITableAttrModifier interfaces aggregated on the kTableModelBoss provide access to and mutation of table attributes; however, we recommend you use suites and facades whenever possible. ICellStyleSuite and ICellStylesFacade ICellStyleSuite is the selection suite used to manipulate cell styles, like creating and editing the cell styles of selected cells; applying a cell style to the current cell selection; and getting and setting local overrides of cell attributes. The facade counterpart of ICellStyleSuite is ICellStylesFacade, aggregated on kUtilsBoss. By using suites and facade, implementation details of cell strands and cell styles storage are encapsulated. We recommend you use only suites and facades. Tables 415 Tables Essential APIs 416 Printing Concepts Printing This chapter provides information about the concepts surrounding the process of printing a publication, including the printing data model and commands, the printing user interface, key interfaces, and how plug-ins can participate in the printing process. Concepts Printing is simply drawing to the printer The implementation and user interface for printing from InDesign and InCopy are similar to those for printing from other Adobe applications, like Photoshop and Illustrator. All these applications use a common component, the Adobe Graphics Manager (AGM), to handle the core printing tasks. Printing from the application entails drawing part or all of a document to a printer rather than to the screen. Adobe applications use Display PostScript, supplied by AGM, to draw graphics primitives to both the screen and the printer. For more information on how document content is drawn to an output device, see the “Graphics Fundamentals” chapter. Control can be shared The tasks of printing from InDesign can be shared among the following: z AGM, which is responsible for PostScript generation. z The InDesign Print plug-in, which is responsible for the user interface, initialization of print settings, and drawing pages. (See “The print action sequence” on page 421.) z Plug-ins that implement various print-related extension patterns, which provide the ability to participate in the printing process carried out by the Print plug-in A plug-in can use printing commands, interfaces, structures, and event-handling mechanisms to print with the C++ API. By understanding the flow of operations in the application’s Print plug-in, you can design a plug-in to participate in the print process and the print user interface by hooking onto the various extensibility points. Third-party plug-in developers do not have direct access to the AGM API. Instead, the application provides the user interface, commands, interfaces, and data structures necessary to drive and participate in the printing process. For details, see “Printing data model” on page 419. Inks and colors When printing a document to any output device, the colors used in a printable item on each page need to be rendered. Depending on the output device and print settings, each color can be separated into multiple inks. This is done so a system like a four-color (CMYK) printing press Printing 417 Printing Concepts can render each printable item. In some cases, printable items can contain spot colors, which generally correspond to a specific ink. Colors, gradients, and spot colors generally are referred to as swatches. A swatch is identified by the IRenderingObject interface. Inks are identified by the IPMInkBossData interface. For more details on inks and colors, see the “Graphics Fundamentals” chapter. Overprinting You can specify the way in which inks are printed on top of one another. Depending on how you set up overprinting, the colors of overlapping items of different colors may appear differently. For more details on overprinting, see InDesign Help. Trapping Trapping allows an output device to compensate for printing problems due to paper misregistration. When the print medium (e.g., paper) is not registered exactly in a multi-color press system, the output can show unintended gaps between inks. An example of a case in which this is especially important is when a printable item has a thin, dark border around a lighter-colored shape. By specifying how trapping is set up, you can compensate for media-registration errors. Color management and proofing What you see on the screen may not always be what you see printed on print media. This is due to variances in how each device used in the design and print process renders colors. For example, your computer monitor may show a bright red apple, but when that is printed on paper using a specific set of inks on a specific output device, the apple may appear to be a different color or brightness. Colors also may shift in the input device, such as digital scanners and cameras. It can be hard to make sure the colors appear as you want on the print media. InDesign and InCopy offer features to manage color throughout the design process. For more details on color management and proofing, see “Color Management” in InDesign Help and the “Graphics Fundamentals” chapter in this document. Preflight and packaging Preflight is a way to verify before you send a publication to the output device that you have all associated files, fonts, assets (e.g., placed images and PDF files), printer settings, trapping styles, and so on. For example, if you placed an image as a low-resolution proxy but do not have the high-resolution original image accessible on your hard disk (or workgroup server), that may result in an error during the printing process. Preflight checks for this sort of problem. For details, see the “Implementing Preflight Rules” chapter. 418 Printing Printing data model Exporting to EPS and PDF Although the user interface for exporting a publication to the EPS and PDF file formats is different from that for printing, the output processes incorporate the same types of drawing components (AGM, inks and color swatches, color management, etc.). Some publishing workflows may incorporate exporting to EPS or PDF as part of the proofing and output steps. Though this document does not go into the details of extending the EPS and PDF export capabilities of the application, you can refer to “Exporting to EPS and PDF” on page 450 for some highlights of how to drive the EPS and PDF export features. Printing data model This section describes the printing data model, commands, interfaces, and structures available in the SDK. InDesign and InCopy can print documents and books to a registered output device. The registered output device can be a printer, PostScript file, or external file format like EPS or PDF. For more information on the PostScript language, see the PostScript Language Reference at http://www.adobe.com/products/postscript/pdfs/PLRM.pdf. Print settings This section describes the data interfaces that make up the print-settings data model. For information on bosses that aggregate these interfaces, see the API reference documentation. The print settings generally are set by the user in either the Print or Print Presets dialog box. (For more information on the Print user interface, see “Print user interface” on page 423.) IPrintData IPrintData is the main data interface that keeps most print-settings data. It also is the interface passed among the print commands during a print operation or in the Print or Print Presets dialog box. Other interfaces that store print settings Printing z IPrintDeviceInfo stores data about printing devices. z IPrintJobData stores data specific to a print job. z IPrintContentPrefs specifies which content (e.g., text, page items, Japanese layout grids, or frame grids) should be printed or omitted from printing. z IOutputPages stores data about pages or spreads to print. z ITrapStyle stores a set of trap settings with a specified name. z IPrintGlyphThresholdPref specifies whether all glyphs of a font are to be downloaded to the output device completely or subsetted. 419 Printing Utility APIs Print preset styles A print preset style is a group of print settings with a specified name. Of the print-settings data model interfaces, the IPrintData and IPrintDeviceInfo data interfaces are stored as part of a print-preset style. A print-preset style is represented by kPrStStyleBoss, and a list of defined print-preset-style boss instances is managed in the kWorkspaceBoss using the IPrStStyleListMgr interface. kPrStStyleBoss also aggregates IGenStyleLockInfo, which specifies whether the style is locked or can be deleted. When a list of print-preset settings is exported to a file (database), the root of that database is an instance of kPrStExportRootBoss, which also aggregates IPrStStyleListMgr. Using this IPrStStyleListMgr interface, you can iterate through the print-preset styles that are stored in the exported file. Trap styles A trap style is a set of trap settings with a specified name. A trap style is represented by kTrapStyleBoss and aggregates the ITrapStyle interface. kTrapStyleBoss also aggregates IGenStyleLockInfo, which specifies whether the style is locked or can be deleted. A trap style is associated with an individual page in a document. A list of trap styles is accessible from ITrapStyleListMgr on kDocWorkspaceBoss (the trap styles used on a document), kWorkspaceBoss (the workspace default trap styles), and kBookBoss (the trap styles used in a book). NOTE: ITrapStyleListMgr does not inherit from IGenStlEdtListMgr like IPrStStyleListMgr does; therefore, the behavior of some ITrapStyleListMgr methods differs from that of any interfaces derived from IGenStlEdtListMgr, and the general style-editing family of APIs (commands like kGenStlEdtExportStylesCmdBoss and interfaces like IGenericSettings) do not apply to trap styles managed in ITrapStyleListMgr. Utility APIs The following utility interfaces are available to facilitate the management and manipulation of print data settings: z IPrintUtils (kUtilsBoss) contains various methods for checking settings on IPrintData. IPrintUtils also has InitializeOutputPages, a method that fills a list of pages to output, given IPrintData and a document. z ITrapStyleUtils (kUtilsBoss) contains methods to facilitate manipulation of trap styles. For details, see the API reference documentation. 420 Printing The print action sequence The print action sequence When you print a document or book in InDesign or InCopy, the application processes a hierarchy of commands. This is the core feature provided by the Print plug-in. This section discusses the sequence of events that take place during the print process and explains the various extensibility points for third-party plug-ins. The primary actions taken by the Print plug-in are as follows: 1. Client code (usually in the form of a menu action or script event) receives two pieces of information: IDocument for the document to be printed and a user-interface options flag indicating which parts of the print user interface should be displayed. The client code creates and executes a specific print-action command, which is one of the following: z kPrintActionCmdBoss — for printing a document in InDesign. z kBookPrintActionCmdBoss — for printing a book in InDesign. z kInCopyPrintActionCmdBoss — for printing a document in InCopy. NOTE: For brief descriptions of these commands, see “Print-action and supporting commands” on page 448. 2. From within the print-action command, a series of supporting print commands is processed. All subsequent steps originate from inside this print-action command. 3. A print-command data interface (IPrintCmdData) used by all print commands gets the IDocument supplied by the client code, along with the UIDRef for the print style (if any), the document’s ink list, and trap-style manager. 4. The print-action command polls print-setup providers (service providers of kPrintSetupService) to determine whether any plug-in wants to participate in the print process by calling IPrintSetupProvider::StartPrintPub (for document printing) or IPrintSetupProvider::StartPrintBook (for book printing). A print-setup provider can either take over the process at this point (including aborting the printing process by means of a flag passed in the parameter list) or perform an action and return control to the Print plug-in. 5. If control returns to the Print plug-in, a non-persistent instance of a print-settings data boss (generally kPrintDataBoss) is created. This is passed around during the rest of the printing process in each supporting print command. 6. The print-action command polls print-setup providers and calls IPrintSetupProvider::BeforePrintUI. A print-setup provider can determine whether to display the print user interface before returning control. After all print-setup providers are polled, the userinterface options flag is examined. If the print user interface is to be shown, the kPrintDialogCmdBoss is created and processed. If the dialog box is opened, the user can modify the settings for this particular print operation. The settings are stored back in the instance of the print-settings data boss created in the previous step. Printing 421 Printing The print action sequence 7. The print-action command polls print-setup providers and calls IPrintSetupProvider::AfterPrintUI. A print-setup provider can either take over the process at this point or perform an action (for example, set the flag indicating whether to show the Save dialog box) and return control to the Print plug-in. If the Save dialog box is to be shown, the kSaveFileDialogBoss is processed. 8. If control returns to the Print plug-in, the print settings data (IPrintData) is saved to the document by means of processing kPrintSavePrintDataCmdBoss (for documents) or kBookSavePrintDataCmdBoss (for books). 9. Data is gathered for the print job. kPrintGatherDataCmdBoss is created but not yet processed. An instance of IOutputPages is created. 10. The print-action command polls print-setup providers and calls IPrintSetupProvider::BeforePrintGatherCmd. A print-setup provider can determine whether to allow processing of the kPrintGatherDataCmdBoss created earlier and whether to return control. 11. If control returns, the print-action command polls print-setup providers and calls IPrintSetupProvider::AfterPrintGatherCmd. A print-setup provider can determine whether to quit here or return control to the Print plug-in. 12. If control returns, a core print command (kNewPrintCmdBoss if running in InDesign or kInCopyNewPrintCmdBoss if running in InCopy) is created and processed. This is where the document or book data actually is sent to the output device. 13. If an error occurs during the core print command, it polls print-setup providers and calls IPrintSetupProvider::PrintErrorEvent. A print-setup provider can handle the print event and determine whether the error message should be displayed to the user. The global error code is set, and the core print command is aborted. 14. If no errors occurred in the core print command, the print-action command saves the print data again (in case it changed during printing). 15. The print process ends. The print-action command polls print-setup providers and calls IPrintSetupProvider::EndPrint. This is the final opportunity for print-setup providers to participate in the print process. Common print interfaces The following are the data interfaces used during the print-action sequence and supporting commands: 422 z IPrintCmdData stores most print settings. IPrintCmdData is used commonly among the print commands. z IPrintData stores most print settings data. (See “IPrintData” on page 419.) z IOutputPages stores data about pages or spreads to print. z IBookPrintData stores book-printing options for the kBookSavePrintDataCmdBoss. z IPrintJobData stores data specific to a print job. Printing Print user interface z IPrintDialogCmdData stores data for the kPrintDialogCmdBoss. z IPrintContentPrefs specifies which content (e.g., text, page items, Japanese layout grids, and frame grids) should be printed or omitted from printing. z IInCopyGalleySettingData stores settings used to construct the Galley panel and contains information about the constructed Galley panel for printing and PDF export in InCopy. Print user interface The print user interface lets an end user change print settings during a print process or in print preset styles. This section describes the design of the Print and Print Presets dialog boxes and how they are invoked, and it presents an overview of how to extend these dialog boxes. Print dialog box The Print dialog box shows the current print settings for the frontmost document. This dialog box opens when the user chooses File > Print in InDesign or chooses one of the print preset styles from the File > Print Presets menu. The Print dialog box also opens when the user chooses Print from the Book panel. This dialog box is invoked programmatically in InDesign by processing the kPrintDialogCmdBoss command. NOTE: An InCopy version of the Print dialog box is invoked by processessing the kInCopyPrintDialogCmdBoss box. This section focuses on the InDesign version of the Print dialog box. The Print dialog box is a selectable dialog box, which contains a list of panels that are selectable by a list (located on the left-hand side of the dialog box). The Print dialog box contains the following panels: z General z Setup z Marks And Bleed z Output z Graphics z Color Management z Advanced z Summary The panels are shown in order in the following sections. Below a screen shot of each panel is a list of methods on the print data-model interfaces (e.g., IPrintData) corresponding to each user-interface element on the panel. For details on these settings, see InDesign CS4 Help. Printing 423 Printing Print user interface Print dialog box: General panel FIGURE 202 Print dialog box: General panel The three user-interface elements above the selectable panel region of the dialog box are common in all Print dialog box screenshots and are mapped to the following API methods: z Style Name — IPrintData::SetStyleName z Printer — IPrintDeviceInfo::UpdatePrinterInfo (which calls IPrintData::SetPrinter internally. Get with IPrintData::GetPrinter.) z PPD — IPrintDeviceInfo::UpdatePrinterInfo (which calls IPrintData::SetPPDFile and IPrintData::SetPPDName internally. Get with IPrintData::GetPPDFile and IPrintData::GetPPDName.) NOTE: Generally, there is a corresponding Get method for each Set method. The user-interface elements on the General panel are mapped to the API methods listed in Table 99. TABLE 99 Print dialog box: General panel 424 User-interface element API method Copies IPrintData::SetCopies Collate IPrintData::SetCollate Printing Print user interface User-interface element API method Reverse Order IPrintData::SetReverseOrder Pages: All IPrintData::SetWhichPages(IPrintData::kAllPages) Pages: Range IPrintData::SetWhichPages(IPrintData::kPageRange) (Range text edit box): IPrintData::SetPageRange Sequence IPrintData::SetPrintOption, using IPrintData::kBothPages (for All Pages), IPrintData::kEvenPagesOnly, or IPrintData::kOddPagesOnly Spreads IPrintData::SetSpreads Print Master Pages IPrintData::SetScope, using IPrintData::kScopeMaster or IPrintData::kScopeDocument Print Non-printing Objects IPrintData::SetPrintNonPrintingObjects Print Blank Pages IPrintData::SetPrintBlankPages Print Visible Guides and Baseline Grids IPrintData::SetPrintWYSIWYGGridsGuides Print dialog box: Setup panel FIGURE 203 Printing Print dialog box: Setup panel 425 Printing Print user interface The user-interface elements on the Setup selectable panel are mapped to the API methods listed in Table 100. TABLE 100 Print dialog box: Setup panel 426 User-interface element API method Paper Size IPrintData::SetPaperSizeSelection if defined by the user (IPrintData::kPaperSizeDefinedByUser), printer driver (IPrintData::kPaperSizeDefinedByDriver), or IPrintData::SetPaperSizeName Paper Size: Width IPrintData::SetCustomPaperWidth only if Paper Size is defined by the user; otherwise (if defined by driver or papersize name), IPrintData::SetCustomPaperWidth(IPrintData::kCustomPap erSizeAuto) Paper Size: Height IPrintData::SetCustomPaperHeight only if Paper Size is defined by user; otherwise (if defined by driver or paper-size name), IPrintData::SetCustomPaperHeight(IPrintData::kCustomPap erSizeAuto) Offset IPrintData::SetCustomPaperOffset only if Paper Size is defined by the user Gap IPrintData::SetCustomPaperGap only if Paper Size is defined by the user Transverse IPrintData::SetPaperOrientation, using IPrintData::kTransverse or IPrintData::kNormal Orientation IPrintData::SetPageOrientation, using IPrintData::kPortrait, IPrintData::kLandscape, IPrintData::kReversePortrait, or IPrintData::kReverseLandscape Scale (radio button) IPrintData::SetScaleMode using IPrintData::kScaleXAndY Scale: Width IPrintData::SetXScale Scale: Height IPrintData::SetYScale Scale: Constrain Proportions IPrintData::SetProportional Scale to Fit (radio button) IPrintData::SetScaleMode using IPrintData::kScaleToFit Page Position IPrintData::SetPagePosition, using IPrintData::kPagePositionUpperLeft, IPrintData::kPagePositionCenterHorizontally, IPrintData::kPagePositionCenterVertically, or IPrintData::kPagePositionCentered Printing Print user interface User-interface element API method Print Layers IPrintData::SetPrintLayers using kPrintAllLayers, kPrintVisibleLayers, or kPrintVisiblePrintableLayers. Thumbnails IPrintData::SetTileThumbMode, using IPrintData::kThumbnails or IPrintData::kTileThumbOff Per Page IPrintData::SetNumberOfThumbsPerPage. Calculate the number of thumbnails on the page (e.g., 4x4 = 16). Tile IPrintData::SetTileThumbMode, using IPrintData::kTiling or IPrintData::kTileThumbOff Overlap IPrintData::SetTilingOverlap Print dialog box: Marks and Bleed panel FIGURE 204 Print dialog box: Marks And Bleed panel (Roman feature set) The user-interface elements on the Marks And Bleed selectable panel are mapped to the API methods listed in Table 101. Printing 427 Printing Print user interface TABLE 101 Print dialog box: Marks and Bleed panel 428 User-interface element API method All Printer’s Marks Checking this sets the state of the five check boxes below it. Crop Marks IPrintData::SetCropMarks Bleed Marks IPrintData::SetBleedMarks Registration Marks PrintData::SetRegistrationMarks Color Bars IPrintData::SetColorBars Page Information PrintData::SetPageInformation Type IPrintData::SetPageMarkFile. For the Roman and Japanese feature sets, you get the Default setting; in this case, the PMString passed into SetPageMarkFile is blank. There are extra details when using the Japanese feature set; see “Japanese page-mark files” on page 449. Weight IPrintData::SetMarkLineWeight, using the enumerations ranging from IPrintData::kMarkLineWeight125pt to IPrintData::kMarkLineWeight30mm (see IPrintData.h.) Offset IPrintData::SetPageMarkOffset Use Document Bleed Settings IPrintData::SetUseDocumentBleed Bleed (chain button) IPrintData::SetBleedChain Bleed: Top IPrintData::SetBleedTop Bleed: Bottom IPrintData::SetBleedBottom Bleed: Inside IPrintData::SetBleedInside Bleed: Outside IPrintData::SetBleedOutside Include Slug Area IPrintData::SetIncludeSlug Printing Print user interface Print dialog box: Output panel FIGURE 205 Print dialog box: Output panel The user-interface elements on the Output selectable panel are mapped to the API methods listed in Table 102. TABLE 102 Print dialog box: Output panel Printing User-interface element API method Color IPrintData::SetOutputMode, using IPrintData::kCompositeLeaveUnchanged, IPrintData::kCompositeGray, IPrintData::kCompositeRGB, IPrintData::kCompositeCMYK, IPrintData::kSeparationBuiltIn, or IPrintData::kSeparationInRIP Text as Black IPrintData::SetPrintColorsInBlack Trapping IPrintData::SetTrappingMode, using IPrintData::kTrappingNone, IPrintData::kTrappingBuiltIn, or IPrintData::kTrappingInRIP 429 Printing Print user interface 430 User-interface element API method Flip IPrintData::SetFlipMode, using IPrintData::kFlipOff, IPrintData::kFlipHorizontal, IPrintData::kFlipVertical, or IPrintData::kFlipBoth Negative IPrintData::SetNegative Screening When the IPrintData::GetOutputMode is a separation mode, IPrintData::SetSeparationScreenText; when the IPrintData::GetOutputMode is a composite mode, IPrintData::SetCompositeScreenText. Frequency If output mode is kCompositeGray and the composite-screen mode is string key “kCustom” (translates differently in each locale), IPrintData::SetCompositeFrequency. Angle If output mode is kCompositeGray and the composite-screen mode is string key “kCustom” (translates differently in each locale), IPrintData::SetCompositeAngle. Simulate Overprint IPrintData::SetSpotOverPrint, using IPrintData::kSimulatePress (if the radio button is checked) or IPrintData::kLegacy (if the radio button is not checked). Inks Stored temporarily in IPrintDialogData::SetNthInkScreening. When the user clicks the OK button in the Ind Manager dialog box, the kChangeInkCmdBoss command is processed for each ink listed. Printing Print user interface Print dialog box: Graphics panel FIGURE 206 Print dialog box: Graphics panel The user-interface elements on the Graphics selectable panel are mapped to the API methods listed in Table 103. TABLE 103 Print dialog box: Graphics panel Printing User-interface element API method Images: Send Data IPrintData::SetImageData, using IPrintData::kImageDataAll, IPrintData::kImageDataOptimized, IPrintData::kImageDataLoRez, or IPrintData::kImageDataProofPrint Fonts: Download IPrintData::SetFontDownload, usingIPrintData::kFontDownloadNone, IPrintData::kFontDownloadComplete, IPrintData::kFontDownloadSubset, or IPrintData::kFontDownloadSubsetLrg Download PPD Fonts IPrintData::SetDownloadPPDFonts PostScript IPrintData::SetPSLangLevel, using IPrintData::kPSLangLevel_2 or IPrintData::kPSLangLevel_3 431 Printing Print user interface User-interface element API method Data Form at IPrintData::SetImageDataFormat, using IPrintData::kImageDataBinary or IPrintData::kImageDataASCII Print dialog box: Color Management panel FIGURE 207 Print dialog box: Color Management panel The user-interface elements on the Color Management selectable panel are mapped to the API methods listed in Table 104. TABLE 104 Print dialog box: Color Management panel 432 User-interface element API method Print: Document IPrintData::SetSourceSpace(IPrintData::kDocumentSourceS pace) Print: Proof IPrintData::SetSourceSpace(IPrintData::kProofSourceSpace) Color Handling IPrintData::SetProfileType, using IPrintData::kUseDocumentProfile, IPrintData::kUsePostScriptCMS, or IPrintData::kUseNoCMS Printing Print user interface User-interface element API method Printer Profile IPrintData::SetProfileType, using IPrintData::kUseDocumentProfile or IPrintData::kUseWorkingProfile. If this is not one of the predefined profiles, use IPrintData::kUseSpecificProfile and then call IPrintData::SetProfileName, specifying the name of the profile as displayed in the drop-down list. Preserve CMYK Colors IPrintData::SetPreserveColorNumbers Simulate Paper Color IPrintData::SetIntent, using IPrintData::kRelativeColorimetric (if the radio button is unselected) or IPrintData::kAbsoluteColorimetric (if the radio button is selected). Print dialog box: Advanced panel FIGURE 208 Print dialog box: Advanced panel The user-interface elements on the Advanced selectable panel are mapped to the API methods listed in Table 104. Printing 433 Printing Print user interface TABLE 105 Print dialog box: Advanced panel User-interface element API method OPI Image Replacement IPrintData::SetOPIReplacement Omit for OPI: EPS IPrintData::SetOmitEPS Omit for OPI: PDF IPrintData::SetOmitPDF Omit for OPI: Images IPrintData::SetOmitImages Transparency Flattener: Preset IPrintData::SetFlattenerStyleName Transparency Flattener: Ignore Spread Overrides IPrintData::SetIgnoreSpreadOverrides Print dialog box: Summary panel FIGURE 209 Print dialog box: Summary panel When you click the Save Summary button, the Save File dialog box opens, asking for the path of a text file to which to save the summary. If you call IPrStStyleListMgr::GetNthStyleDescrip- 434 Printing Printing extension patterns tion for a selected printer style, you get the same text as shown in the Summary multi-line text widget. Print Presets dialog box The main Print Presets dialog box is opened when the user chooses File > Print Presets > Define. In the main Print Presets dialog box, the user can see the currently defined print presets and a text summary of the currently selected preset. The main dialog box also has buttons for creating a new print preset (New), editing an existing print preset (Edit), deleting the selected print preset (Delete), loading from a print presets file (Load), and saving the print presets to a file (Save). When the user clicks the New or Edit button, a selectable dialog box similar to the Print dialog box opens. The design of the Print Presets selectable dialog box is mostly the same as the Print dialog box, with a few minor differences: z The title of the dialog box differs based on what the end user is doing. z The thumbnail image on the bottom-left corner of the dialog box is shown only in the Print dialog box and is disabled in the Print Presets dialog box. z The Print dialog box has a Save Preset button, which allows the user to save the current print settings as a print-preset style in the workspace. The Print Presets dialog box does not have that button, since the Print Presets dialog box is where you edit the print-preset style. Extending the Print dialog box or the Print Presets selectable dialog box The Print dialog box and the Print Presets selectable dialog boxes are extensible by third-party plug-ins by means of custom, selectable, dialog panel. By implementing one selectable dialog panel, you can add your own panel into both the Print dialog box and the Print Presets selectable dialog box. For a discussion on SDK sample plug-ins that implement selectable dialog panels, see “Adding your own panel to the Print and Print Presets dialog boxes” on page 446. Printing extension patterns Print-setup provider A plug-in can register a print-setup service boss by providing an IK2ServiceProvider implementation that supports the kPrintSetupService service ID. The service is called at various points during the print-action sequence (see “The print action sequence” on page 421). The implementation for IPrintSetupProvider provides methods to set up or change print parameters before and during the printing process. See Table 106 for implementation details. Printing 435 Printing Printing extension patterns TABLE 106 Implementation recipe for a print-setup provider Purpose Participate in various phases in the print process. ServiceID kPrintSetupService Required companion interface IPrintSetupProvider Boss class IID_IK2SERVICEPROVIDER with implementation ID kPrintSetupServiceImpl (see PrintID.h) and IID_IPRINTSETUPPROVIDER with your implementation ID When called Methods of IPrintSetupProvider are called at various phases of the print action command. See “The print action sequence” on page 421. How called All providers of this ServiceID get called. Sample code See “Participating in the stages of the print-action sequence” on page 443. Print-insert-PostScript proc provider A plug-in can inject PostScript statements into the print-output stream by registering an IK2ServiceProvider implementation supporting the kPrintInsertPSProcService serviceID and providing an implementation for IPrintInsertPSProcProvider. See Table 107 for implementation details. TABLE 107 Implementation recipe for a print-insert-PostScript proc provider 436 Purpose Inject PostScript comments at predetermined phases of the printing process. ServiceID kPrintInsertPSProcService Required companion interface IPrintInsertPSProcProvider Boss class IID_IK2SERVICEPROVIDER with implementation ID kInsertPSProcServiceImpl (see PrintID.h) and IID_IPRINTINSERTPSPROCPROVIDER with your implementation ID Printing Printing extension patterns When called Methods of IPrintInsertPSProcProvider are called at various phases of the core print command. See “The print action sequence” on page 421. The Setup method is called first, to give the provider a chance to store print settings. Then the GetInsertPSProcName method is called, so the provider can return a name. (The following steps occur only if your GetInsertPSProcName implementation returns a non-empty string.) The GetClientData method gets called to obtain the provider’s custom client data (if any), then the PrintInsertPSProc method is called at various phases of the printing process. (For a list of phases, see the enum IPrintInsertPSProcProvider::DocumentSection.) How called All providers of this ServiceID get called. Sample code See “Injecting PostScript comments or extra data into the print stream during the print action sequence” on page 444. Print-data helper-strategy provider A plug-in can control whether to override the current locked state and relevant state of print data items in the Print dialog box by registering an implementation of IK2ServiceProvider supporting the kPrintDataHelperStrategyService serviceID. The IPrintDataHelperStrategy interface provides two methods: IsLocked and IsRelevant. IsLocked allows a plug-in to lock the Print and Print Presets dialog-box user-interface elements. Although an item's locked state can be partially controlled using this method, the application print components are still free to change an item's value as necessary to maintain the print data in a consistent and valid context. IsRelevant allows a plug-in to disable specific Print and Print Presets dialog-box user-interface elements. Although an item's relevant state can be partially controlled using this interface, the application print components are still free to change an item's value as necessary to maintain the print data in a consistent and valid context. The most restrictive interface takes precedence. After an ID is set to be locked (the most restrictive setting), other implementations are not called. After an ID’s relevance is set to kFalse (the most restrictive setting), other implementations are not called. See Table 108 for implementation details. TABLE 108 Implementation recipe for a print-data helper-strategy provider Printing Purpose Influence the Print and Print Presets dialog boxes through the ability to suppress and lock print user-interface elements. ServiceID kPrintDataHelperStrategyService Required companion interface IPrintDataHelperStrategy 437 Printing Printing solutions Boss class IID_IK2SERVICEPROVIDER with implementation ID kDataHelperStrategyServiceImpl(see PrintID.h) and IID_IPRINTDATAHELPERSTRATEGY with your implementation ID When called Whenever IPrintData::IsLocked or IPrintData::IsRelevant is called. Generally this happens when the Print or Print Presets dialog box is being prepared for display. How called All providers of this ServiceID get called. Related sample code See “Specifying which parts of the Print and Print Presets dialog boxes are relevant or locked” on page 447. Draw-event handlers A plug-in can register a draw-event handler (IDrwEvtHandler) to participate in various draw events that happen during the printing process. For more details on draw-event handlers, including implementation details, see the “Graphics Fundamentals” chapter. For samples that implement this extension pattern for printing purposes, see “Adding a custom watermark during the printing process” on page 444 and “Injecting PostScript comments or extra data into the print stream during the print action sequence” on page 444. Printing solutions Getting started Printing a document Execute (not process) one of the following commands: z kPrintActionCmdBoss, to print a document in InDesign z kInCopyPrintActionCmdBoss, to print a document in InCopy The minimal settings required to print a document with kPrintActionCmdBoss in InDesign are as follows: z The document you want to print. z The range of pages in the document you want to print. z Print user-interface options. The print-action command is executed (not processed), because there is no undo capability provided. For a sample that uses either kPrintActionCmdBoss or kInCopyPrintActionCmdBoss, see the SnpPrintDocument.cpp sample code snippet, in particular SnpPrintDocument::DoPrintDocument. 438 Printing Printing solutions Printing a Book Execute the kBookPrintActionCmdBoss command. Working with print-preset styles Getting information about print-preset styles Query for IPrStStyleListMgr on kWorkspaceBoss, then call the Get methods to get information about the print-preset styles that are registered. IPrStStyleListMgr::GetNumStyles reports the number of print-preset styles registered. IPrStStyleListMgr::GetNthStyleName reports the name of the print-preset style at index n. IPrStStyleListMgr::GetNthStyleRef returns the UIDRef of the print-preset style at index n. Using this UIDRef, you can query IPrintData, and get further information about the print-preset style. There are other useful methods on IPrStStyleListMgr. NOTE: IPrStStyleListMgr.h does not declare any methods; however, it inherits IGenStlEdtListMgr. See IGenStlEdtListMgr.h for details. For more details, see the SnpManipulatePrintStyles.cpp code snippet, in particular SnpManipulatePrintStyles::InspectPrintStyle. Adding a print-preset style Query for IPrStStyleListMgr on kWorkspaceBoss, then call IPrStStyleListMgr::AddStyle. When the new style is created, it is appended to the end of the list of print-preset styles. For details, see the SnpManipulatePrintStyles.cpp code snippet, in particular SnpManipulatePrintStyles::AddPrintStyle. Duplicating a print-preset style Query for IPrStStyleListMgr on kWorkspaceBoss, then call IPrStStyleListMgr::CopyNthStyle. When the new style is created, it is appended to the end of the list of print-preset styles. Modifying the name of a print-preset style First, query for IPrStStyleListMgr on kWorkspaceBoss. Then, call IPrStStyleListMgr::SetNthStyleName. When you do this, however, the name of the print-preset style stored in IPrintData is not updated, so you must query for IPrintData and call IPrintData::SetStyleName, using the same name. For details, see the SnpManipulatePrintStyles.cpp code snippet, in particular SnpManipulatePrintStyles::ModifyPrintStyleName. Modifying the settings of a print-preset style First, query for IPrStStyleListMgr on kWorkspaceBoss. Then, call IPrStStyleListMgr::EditNthStyle, which invokes the Print Presets selectable dialog box. This procedure requires a user to use the dialog box to change settings. For details, see the SnpManipulatePrintStyles.cpp code snippet, in particular SnpManipulatePrintStyles::ModifyPrintStyle. Printing 439 Printing Printing solutions Deleting a print-preset style Query for IPrStStyleListMgr on kWorkspaceBoss, then call IPrStStyleListMgr::DeleteNthStyle. For details, see the SnpManipulatePrintStyles.cpp code snippet, in particular SnpManipulatePrintStyles::DeletePrintStyle. Exporting a set of print-preset styles to a file Process the kGenStlEdtExportStylesCmdBoss command. In the IGenStlEdtCmdData data interface, call SetListMgrIID to set the type of style list to be the print style list, by specifying the IPrStStyleListMgr::kDefaultIID (IID_IPRSTSTYLELISTMGR), then call SetTargetFile to specify the full path of the file to save. Optionally, specify a set of style indices you want to export from IPrStStyleListMgr on kWorkspaceBoss. If you do not specify a set of style indices, all styles stored in IPrStStyleListMgr are exported. Importing a set of print-preset styles from a file Process the kGenStlEdtImportStylesCmdBoss command. In the IGenStlEdtCmdData data interface, call SetListMgrIID to set the type of style list to be the print style list, by specifying the IPrStStyleListMgr::kDefaultIID (IID_IPRSTSTYLELISTMGR), then call SetTargetFile to specify the full path of the file to import. Getting notified when a print-preset style is imported to/exported from a file Implement a signal-responder extension pattern that responds one or more of the following signals: z kBeforeExportStyleSignalResponderService z kAfterExportStyleSignalResponderService z kBeforeImportStyleSignalResponderService z kAfterImportStyleSignalResponderService These IDs are defined in GenericSettingsID.h. In your implementation of IResponder::Respond, you can query for the IStyleSignalData interface using ISignalMgr::QueryInterface (or InterfacePtr). IStyleSignalData gives you a reference to the file that is the target of the export or import operation. NOTE: 440 Any preset style that is managed by the generic-settings framework and can be exported or imported—such as PDF-export styles and document-preset styles—can be monitored in the same way. Printing Printing solutions Working with trap styles Getting information about trap styles First, query for ITrapStyleListMgr on one of the following bosses: z kWorkspaceBoss, for trap styles registered in the workspace (also used as document defaults when a new document is created) z kDocWorkspaceBoss, for trap styles registered in a document z kBookBoss, for trap styles registered in a book The utility interface ITrapStyleUtils (on kUtilsBoss) has a QueryTrapStyleListMgr method to simplify this process. There are two overloaded methods: z The one that takes IDocument* returns the ITrapStyleListMgr on kDocWorkspaceBoss (i.e., the workspace related to the document). z The one that takes a UIDRef returns the ITrapStyleListMgr on the same boss as the UIDRef, or the ITrapStyleListMgr on kWorkspaceBoss if the UID in the UIDRef is kInvalidUID. Next, call the Get methods to get various information about the trap styles that are registered. ITrapStyleListMgr::GetNumStyles reports the number of trap styles registered. ITrapStyleListMgr::GetNthStyleName reports the name of the trap style at index n. ITrapStyleListMgr::GetNthStyleRef returns the UIDRef of the trap style at index n. Using this UIDRef, you can query ITrapStyle and get further information about this trap style. There are other useful methods on ITrapStyleListMgr. NOTE: ITrapStyleListMgr does not inherit from IGenStlEdtListMgr the way IPrStStyleListMgr does. For details, see the SnpManipulateTrapStyles.cpp code snippet, in particular SnpManipulateTrapStyles::InspectTrapStyle. Adding a trap style Query for ITrapStyleListMgr, then call ITrapStyleListMgr::AddStyle. When the new style is created, it is appended to the end of the list of trap styles. For details, see the SnpManipulateTrapStyles.cpp code snippet, in particular SnpManipulateTrapStyles::AddTrapStyle. Duplicating a trap style Query for ITrapStyleListMgr, then call ITrapStyleListMgr::CopyNthStyle. When the new style is created, it i appended to the end of the list of trap styles. Modifying a trap style Query for ITrapStyleListMgr, then call ITrapStyleListMgr::EditNthStyle. You are required to pass in the trap-style data via the parameter list as ITrapStyle. You can create a non-persistent instance of kTrapStyleBoss to store the settings. For details, see the SnpManipulateTrapStyles.cpp code snippet, in particular SnpManipulateTrapStyles::ModifyTrapStyle. Printing 441 Printing Printing solutions Deleting a trap style Query for ITrapStyleListMgr, then call ITrapStyleListMgr::DeleteNthStyle. For details, see the SnpManipulateTrapStyles.cpp code snippet, in particular SnpManipulateTrapStyles::DeleteTrapStyle. Exporting a set of trap styles to another trap-style list First, create a command sequence, as the following procedure processes multiple commands. Next, query for ITrapStyleListMgr, then call ITrapStyleListMgr::ExportStyles. The first parameter is a UIDRef for the destination trap style list (note the source trap style list is identified by this particular instance of ITrapStyleListMgr), and that UIDRef must refer to a boss that aggregates ITrapStyleListMgr. If you want to export the trap styles to a file, you can create a new database using DBUtils::CreateDataBase and IDataBase::New, then put a new root UID by calling IDataBase::NewUID. The class for the new root should be kTrapStyleExportRootBoss. Create a UIDRef for this new root, and pass it into ITrapStyleListMgr::ExportStyles. Once that completes, save the database by calling IDataBase::SaveAs, and close the database by deleting the IDataBase pointer. Importing a set of trap styles from another trap-style list First, create a command sequence, as the following procedure processes multiple commands. Next, query for ITrapStyleListMgr, then call ITrapStyleListMgr::ImportStyles. The first parameter is a UIDRef for the source trap style list (note the destination trap style list is identified by this particular instance of ITrapStyleListMgr), and that UIDRef must refer to a boss that aggregates ITrapStyleListMgr. If you want to import the trap styles from a file, you can open a database using DBUtils::CreateDataBase and IDataBase::Open, then get the root UID by calling IDataBase::GetRootUID. The class for the new root should be kTrapStyleExportRootBoss. Create a UIDRef for this root, and pass it into ITrapStyleListMgr::ImportStyles. Once that completes, close the database by deleting the IDataBase pointer. Determining which trap style is associated with a page on a document Given a specific page (kPageBoss) on a document (which you can query using IPageList on kDocBoss), query for IPersistUIDData with the specific IID of IID_ITRAPSTYLEUIDDATA. Get the UID from IPersistUIDData. That UID refers to the trap style registered in ITrapStyleListMgr on the document workspace (kDocWorkspaceBoss). To find out the name of this trap style, first call ITrapStyleListMgr::GetStyleIndexByUID and then call ITrapStyleListMgr::GetNthStyleName. Alternately, you can collect a list of pages that use a specific trap style. Call ITrapStyleUtils::GetDocumentTrapStylePageList. For details, see the SnpManipulateTrapStyles.cpp code snippet, specifically SnpManipulateTrapStyles::InspectTrapStyle. Associating a trap style with a page on a document Create a UIDList of pages (kPageBoss) to which you want to associate a trap style, and the UIDRef of the trap style. Then call ITrapStyleUtils::AssignStyleToPageList. For details, see the SnpManipulateTrapStyles.cpp code snippet, specifically SnpManipulateTrapStyles::AssignTrapStyleToPages. 442 Printing Printing solutions Participating in the print process Participating in the stages of the print-action sequence There are various ways to participate in the print-action sequence. The main way is to implement a print-setup provider (see “Print-setup provider” on page 435). By implementing IPrintSetupProvider, your plug-in can be notified at the stages of the print-action sequence described in “The print action sequence” on page 421. Other ways to participate in the print-action sequence are noted in the following list. Some of these require extra hook-ups from within a print setup-provider implementation. z Implement a print-insert PostScript proc provider to inject PostScript statements into the print-output stream. (See “Print-insert-PostScript proc provider” on page 436 and “Injecting PostScript comments or extra data into the print stream during the print action sequence” on page 444.) z Implement a print-data-helper strategy provider to influence the display of the Print and Print Presets dialog boxes. (See “Print-data helper-strategy provider” on page 437 and “Specifying which parts of the Print and Print Presets dialog boxes are relevant or locked” on page 447.) z Implement a draw-event handler that handles print-related drawing events. (See “Drawevent handlers” on page 438, “Adding a custom watermark during the printing process” on page 444, “Specifying which page items should be printed” on page 443, and “Injecting PostScript comments or extra data into the print stream during the print action sequence” on page 444). z Implement a custom write stream so the print-action sequence writes to it. The custom stream must be specified from one of the methods in your print-setup provider. (See “Writing printing data to a custom stream” on page 447.) The following sample plug-ins contain an implementation of a print-setup provider: z PrintMemoryStream prints document content to a custom memory stream. z PrintSelection adds a flag to the document to print only selected page items. For details, see the API reference documentation for each sample plug-in. Specifying which page items should be printed You can implement a print-setup provider (see “Participating in the stages of the print-action sequence” on page 443) and a custom draw-event handler to specify which pages items should be printed. From the print-setup provider (in any method that gets called before the core print command is executed, the last chance being AfterPrintGatherCmd), you register the custom draw-event handler that handles the print event only when it encounters document content you want to print. When the printing is done, you de-register the custom draw-event handler in your print-setup provider’s EndPrint implementation. The PrintSelection sample plug-in shows how this is done. Here are the highlights of what the PrintSelection plug-in does: Printing 443 Printing Printing solutions z In PrnSelPrintSetupProvider::AfterPrintUI, the currently selected page items are gathered and the custom draw-event handler is registered for the draw event message kDrawShapeMessage. z In PrnSelPrintSetupProvider::BeforePrintGatherCmd, the set of pages to output is modified based on which pages contain the selected page items. z The PrnSelDrawHandler::HandleEvent determines whether the current printable item should be printed. This draw event handler does not do any drawing; the actual drawing of the printable item is delegated to other draw-event handlers. z In PrnSelPrintSetupProvider::EndPrint, the custom draw-event handler is unregistered. For details, see the API reference documentation for the PrintSelection plug-in. Specifying which layer(s) of a document should be printed In the Setup panel of the Print dialog box, there is a setting called “Print Layers,” which is a drop-down list that allows the user to choose printing with visible and printable layers, visible layers, or all layers. This option can be get/set through the IPrintData::GetPrintLayers/SetPrintLayers methods. Each layer’s visibility and printability, however, are managed by layer options as described in the “Layer Options” section of the “Layout Fundamentals” chapter. To set the visibility of a layer, use the kShowLayerCmdBoss command. To set the printability of a layer, use the kPrintLayerCmdBoss command. The SnpPrintDocument.cpp SDK snippet shows how to use a kPrintLayerCmdBoss. Before processing a kPrintLayerCmdBoss, make sure the printability of the layer is different from the new state you are going to set. If the new printability state is the same as the old one, kPrintLayerCmdBoss asserts, although the assert is benign. Adding a custom watermark during the printing process You can implement a custom draw-event handler that draws the watermark on a page or a page item. This is done in the BasicDrwEvtHandler sample plug-in, a canonical example of a drawevent handler. For details, see the API reference documentation for the BasicDrwEvtHandler plug-in. Another way to add custom watermarks to page items is to implement a page-item adornment that draws when the draw flag has the IShape::kPrinting bit set. While the FrameLabel sample plug-in does not support printing (i.e., if flags contains IShape::kPrinting, the Draw method breaks out), you can use the FrameLabel sample as a basis for implementing custom watermarks and extra persistent data on page items. For details, see the API reference documentation for the FrameLabel plug-in. Injecting PostScript comments or extra data into the print stream during the print action sequence You can implement a print-insert PostScript proc provider (see “Print-insert-PostScript proc provider” on page 436) to inject PostScript comments during predetermined phases of the print-output process as driven by the core print command. The PrintMemoryStream sample plug-in contains an implementation of a print-insert PostScript proc provider. The print-insert PostScript proc provider implementation in this sample is a canonical example that demonstrates when each method in IPrintInsertPSProcProvider gets called by writing a trace mes- 444 Printing Printing solutions sage. This plug-in also demonstrates how to manage custom print settings throughout the print-action sequence. There are other ways to inject PostScript comments into the print stream during the print action sequence: z Implement a custom draw-event handler that calls the IGraphicsPort::AddComment method. For a sample of a draw-event handler that responds to the kDrawShapeMessage for printing, see PrnSelDrawHandler::HandleEvent in the PrintSelection sample plug-in. To obtain IGraphicsPort, you can first get a pointer to the GraphicsData from DrawEventData::gd, then call GraphicsData::GetGraphicsPort. z Add custom registration marks on each page, if you are using the Japanese feature set of InDesign or InCopy. See “Japanese page-mark files” on page 449. Adding custom print settings so they are managed like other print settings Old method First, write your own interface that allows you to manipulate your custom print-settings data (e.g., IMyPrintData). Then, the simplest way to persist your custom print settings is to add a persistent implementation of this interface (e.g., kMyPrintDataImpl) on a boss class that also is persisted with the document, like kDocWorkspaceBoss or kDocBoss. By adding your implementation only in the specified boss classes, however, you will not be able to manage your custom print settings together with print-preset styles. In addition, there are several places where you must copy your custom print-setting data, as new instances of the aforementioned bosses are created (during processes like the print-action sequence and the Print Presets dialog) for the purpose of adding a print preset style or keeping a temporary instance for use during the print-action sequence. For print-data settings stored in IPrintData, the application calls IPrintData::CopyData to copy only the data managed within the IPrintData implementation to these new or temporary instances of the print data boss; however, your custom print settings are not copied at that time. Furthermore, the commands that copy the IPrintData to the appropriate instance print data boss do not notify any subjects. To solve these problems, you can implement a special observer. This observer observes changes that notify on the IID_ICOMMANDMGR protocol on a command’s target database. By knowing which commands copy IPrintData and when the data is copied, you can manage your custom print settings as the same time. New method Beginning in CS4, a new kPrintCopyCustomDataService is available; any plug-in that registers for this service gets a chance to manage its own print data during the print process. This is the preferred method for managing your own custom print data, instead of using the commandobserver technique discussed above. Note the service provider is called after the application’s CopyData is done. You should provide the implementation for IPrintCopyCustomDataProvider and aggregate it on the service-provider boss that registered as kPrintCopyCustomDataService. Then your IPrintCopyCustomDataProvider will get called whenever IPrintData::CopyData is called. Printing 445 Printing Printing solutions Adding your own panel to the Print and Print Presets dialog boxes You can implement a panel that adds itself to the dialog box identified by kPrintSelectableDialogService. The panel should be 400 pixels wide and 345 pixels high. The ODFRez widget type should inherit from PrimaryResourcePanelWidget, and the boss class that contains the necessary implementations (see below) should inherit from kPrimaryResourcePanelWidgetBoss. The required implementations in this boss class are as follows: z IK2ServiceProvider (IID_IK2SERVICEPROVIDER), to register the ServiceID values specified in the IPanelCreator::GetServiceIDs method. You do not need to implement this yourself; you can use the implementation ID provided by the application: kDialogPanelServiceImpl (defined in WidgetID.h). z IPanelCreator (IID_IPANELCREATOR), to specify the resource IDs in your ODFRez resource file (.fr) that declares the selectable dialog ServiceID and the panel resource IDs provided by the plug-in. Using this implementation, the IK2ServiceProvider in this boss (kDialogPanelServiceImpl) can get the necessary data to register the panel into the appropriate selectable dialog box. The implementation of this interface must inherit from CPanelCreator. z IDialogController (IID_IDIALOGCONTROLLER), to initialize the panel, validate the settings on the panel when the OK button is clicked, apply the settings on the panel when the OK button is clicked, and perform any clean-up if the user cancels the dialog. The implementation of this interface may inherit from CDialogController. z IObserver (IID_IOBSERVER), to handle user-interface actions for widgets on the panel, as well as widgets on the parent selectable dialog. (To get the widget IDs of the widgets on the parent selectable dialog box, choose QA > Panel Edit Mode in the debug build of the application.) The implementation of this interface must inherit from AbstractDialogObserver (as opposed to CSelectableDialogObserver, which is used in the BasicSelectableDialog sample plug-in). See the API reference documentation for AbstractDialogObserver. In addition to the panel user-interface definition and the supporting boss class, you must include the following resources: z IDList — Specifies the selectable-dialog service ID, which in this case is kPrintSelectableDialogService. z IDListPair — Specifies the selectable-dialog service ID (again, kPrintSelectableDialogService), the resource ID of the panel you want to add to the selectable dialog box, and the PluginID that owns the panel. You can specify multiple panels in this resource. Both these resources should have the resource ID you specified in your IPanelCreator::GetPanelRsrcID implementation. For example, if the resource ID you specify in IPanelCreator::GetPanelRsrcID is kSDKDefIDListPairResourceID, the resource ID of the panel is kSDKDefPanelResourceID, and the ID of the plug-in that provides this panel is kPrtHokUIPluginID, the resources would be written like Example 25. 446 Printing Printing solutions EXAMPLE 25 An IDList and IDListPair to support the kPrintSelectableDialogService resource IDList (kSDKDefIDListPairResourceID) { { kPrintSelectableDialogService, }, }; resource IDListPair (kSDKDefIDListPairResourceID) { { kPrintSelectableDialogService, kSDKDefPanelResourceID, kPrtHokUIPluginID, }, }; To find out whether the panel is being opened from the Print or Print Presets dialog box, you can query the IPrintDialogData interface from the parent selectable dialog (by using the help of IWidgetParent), and call IPrintDialogData::GetFlags. See Example 26. EXAMPLE 26 Getting IPrintDialogData flags from a print-dialog selectable-panel implementation // 'this' maybe a dialog controller or observer InterfacePtr<IWidgetParent> widgetParent(this, UseDefaultIID()); InterfacePtr<IPrintDialogData> printDialogData ((IPrintDialogData*)widgetParent->QueryParentFor(IID_IPRINTDIALOGDATA)); printFlags = printDialogData->GetFlags(); If the returned value has the IPrintDialogData::kWorkingOnStyle bit set (test by doing a logical AND on the value with IPrintDialogData::kWorkingOnStyle), the panel is in the Print Presets dialog box. A canonical implementation of a selectable dialog box (along with children panels) is provided in the BasicSelectableDialog sample plug-in. You can use BasicSelectableDialog to understand the interactions between the parent selectable dialog box and its child panels. For more details, see the API reference documentation associated with the BasicSelectableDialog sample plugin. Specifying which parts of the Print and Print Presets dialog boxes are relevant or locked You can implement a print-data helper strategy provider (see “Print-data helper-strategy provider” on page 437). Print-data helper strategy provider also are called when the Print or Print Presets dialog box gets its summary text. (That is, if a setting is not relevant, it is not included in the summary text.) For a sample implementation of IPrintDataHelperStrategy, see the PrintMemoryStream sample plug-in. Writing printing data to a custom stream You can write a class that implements IPMStream (and inherits CStreamWrite), along with a class that inherits IXferBytes, to copy the data to whatever your stream targets. Your stream may target things like a file, a memory buffer, or even a database. This custom stream must be reported to the print-action sequence by calling IOutputPages::SetOutputStream. You can do this from one of the methods in your print-setup provider (see “Print-setup provider” on Printing 447 Printing Bosses that aggregate IPrintData page 435 and “Participating in the stages of the print-action sequence” on page 443), like IPrintSetupProvider::BeforePrintGatherCmd. For a sample implementation, see the PrintMemoryStream sample plug-in. Bosses that aggregate IPrintData z kBookBoss stores the Custom print settings for a book. z kBookPrintDataBoss stores the print settings when printing a book with the print commands. z kDocWorkspaceBoss stores the Custom print settings for a document. z kInCopyTempPrintDataBoss stores the print settings for temporary use only (InCopy only). z kPrintDataBoss stores the print settings when printing a document with the print commands. This is the most common boss class for storing print settings during the print process. z kPrintDataOnlyBoss stores the print settings for temporary use only. z kPrStStyleBoss stores the print settings for a particular style in the list of defined print preset styles. (See “Print preset styles” on page 420.) z kStylePrintDataBoss stores the print settings for temporary use when generating the human-readable text summary of a print-preset style. This text is displayed in the Print Presets dialog box. For details on these bosses, such as other aggregated interfaces or boss hierarchy, see the API reference documentation. Print-action and supporting commands Table 109 lists the main command bosses used in the print process. TABLE 109 Command bosses used in the print process 448 Command boss Description kBookPrintActionCmdBoss Top-level print-action command for printing a book. For most clients, this is the command to execute to print a book in InDesign. It processes the following supporting commands: kPrintDialogCmdBoss, kBookSavePrintDataCmdBoss, kPrintGatherDataCmdBoss, and kNewPrintCmdBoss. kBookSavePrintDataCmdBoss Saves the print data into a book. Printing Japanese page-mark files Command boss Description kCreatePrintGalleyViewCmdBoss Creates a galley window view to print. kInCopyNewPrintCmdBoss Performs the actual output of a document in InCopy. kInCopyPrintActionCmdBoss Top-level print-action command for printing in InCopy. For most clients, this is the command to execute to print a document in InCopy. It processes the following supporting commands: kCreatePrintGalleyViewCmdBoss, kInCopyPrintDialogCmdBoss, kInCopyNewPrintCmdBoss, and kPrintGatherDataCmdBoss. kInCopyPrintDialogCmdBoss Displays the print dialog box in InCopy. kNewPrintCmdBoss Performs the actual output of a document or a book to the output device in InDesign. kPrintActionCmdBoss Top-level print-action command for printing a document. For most clients, this is the command to execute to print a document in InDesign. It processes the following supporting commands: kPrintDialogCmdBoss, kPrintSavePrintDataCmdBoss, kPrintGatherDataCmdBoss, and kNewPrintCmdBoss. kPrintDialogCmdBoss Displays the print dialog box in InDesign. kPrintGatherDataCmdBoss Gathers print data. kPrintSavePrintDataCmdBoss Saves the print data into a document. Japanese page-mark files The Japanese feature set provides two extra Type options in the Marks And Bleed panel in the Print dialog box and Print Presets selectable dialog box: z Maru-tsuki Sentaa-tombo — The untranslated string key “kJMarksWithCircle” is passed into IPrintData::SetPageMarkFile. z Maru-nashi Sentaa-tombo — The untranslated string key “kJMarksWithoutCircle” is passed into IPrintData::SetPageMarkFile. In addition (with either the Roman or Japanese feature set), you can specify a filename (without path or extension) of a file that contains a custom page mark written using PostScript. The contents of this PostScript file are injected during printing. The actual file should have an .mrk extension and be in one of the following locations: Printing (Windows) C:\Program Files\Common Files\Adobe\PrintSpt (Mac OS) /Library/Application Support/Adobe/PrintSpt 449 Printing Exporting to EPS and PDF Exporting to EPS and PDF The process of exporting to EPS and PDF file formats is somewhat similar to the process of printing, in that similar components of the application are employed. The way you drive the export process and the data model behind the EPS and PDF export features are somewhat different. This section provides highlights of how to drive the EPS and PDF export features in the application. Exporting to EPS EPS export preferences Settings for EPS export are stored in the IEPSExportPreferences interface on kWorkspaceBoss. For details, see the API reference documentation. To get the preferences, query for IEPSExportPreferences on kWorkspaceBoss and call its Get methods. To modify the preferences, process the kSetEPSExportPrefsCmdBoss command. This command has a data interface, IEPSExportPrefsCmdData, with which you specify the new values of the EPS preferences. Before you call any Set methods, you can call IEPSExportPrefsCmdData::CopyPrefs to copy the current preference settings in IEPSExportPreferences. User interface When you choose File > Export and specify the file to export and the export format to be EPS, you will see a selectable dialog box with two panels, General and Advanced. The user-interface elements on these panels are mapped to the methods on IEPSExportPreferences, as described below. 450 Printing Exporting to EPS and PDF Export EPS dialog box: General panel FIGURE 210 Printing Export EPS dialog box: General panel z All Pages — IEPSExportPreferences::SetEPSExPageOption using IEPSExportPreferences::kExportAllPages z Ranges (radio button) — IEPSExportPreferences::SetEPSExPageOption using IEPSExportPreferences::kExportRanges z Ranges (text-edit box) — IEPSExportPreferences::SetEPSExPageRange z Spreads — IEPSExportPreferences::SetEPSExReaderSpread using IEPSExportPreferences::kExportReaderSpreadOFF or IEPSExportPreferences::kExportReaderSpreadON z PostScript — IEPSExportPreferences::SetEPSExPSLevel using ences::kExportPSLevel2 or IEPSExportPreferences::kExportPSLevel3 z Color — IEPSExportPreferences::SetEPSExColorSpace, using IEPSExportPreferences::kExportPSColorSpaceLeaveUnchanged, IEPSExportPreferences::kExportPSColorSpaceDIC, IEPSExportPreferences::kExportPSColorSpaceCMYK, IEPSExportPreferences::kExportPSColorSpaceGray, or IEPSExportPreferences::kExportPSColorSpaceRGB z Preview — IEPSExportPreferences::SetEPSExPreview using IEPSExportPreferences::kExportPreviewNone, IEPSExportPreferences::kExportPreviewTIFF, or IEPSExportPreferences::kExportPreviewPICT (Mac OS only) z Embed Fonts — IEPSExportPreferences::SetEPSExIncludeFonts using IEPSExportPreferences::kExportIncludeFontsNone, IEPSExportPreferences::kExportIncludeFontsWhole, IEPSExportPreferences::kExportIncludeFontsSubset, or IEPSExportPreferences::kExportIncludeFontsSubsetLarge IEPSExportPrefer- 451 Printing Exporting to EPS and PDF z Data Format — IEPSExportPreferences::SetEPSExDataFormat, using IEPSExportPreferences::kExportASCIIData or IEPSExportPreferences::kExportBinaryData z Bleed: Top — IEPSExportPreferences::SetEPSExBleedTop z Bleed: Bottom — IEPSExportPreferences::SetEPSExBleedBottom z Bleed: Inside — IEPSExportPreferences::SetEPSExBleedInside z Bleed: Outside — IEPSExportPreferences::SetEPSExBleedOutside z If any Bleed settings are over 0 — IEPSExportPreferences::SetEPSExBleedOnOff using either IEPSExportPreferences::kExportBleedON, or IEPSExportPreferences::kExportBleedOFF Export EPS dialog box: Advanced panel FIGURE 211 452 Export EPS dialog box: Advanced panel z Send Data — IEPSExportPreferences::SetEPSExBitmapSampling, using IEPSExportPreferences::kExportBMSampleNormal or kExportBMSampleLowRes z OPI Image Replacement — IEPSExportPreferences::SetEPSExOPIReplace, using IEPSExportPreferences::kExportOPIReplaceON or IEPSExportPreferences::kExportOPIReplaceOFF z Omit for OPI: EPS — IEPSExportPreferences::SetEPSExOmitEPS, using IEPSExportPreferences::kExportOmitEPSON or IEPSExportPreferences::kExportOmitEPSOFF z Omit for OPI: PDF — IEPSExportPreferences::SetEPSExOmitPDF, using IEPSExportPreferences::kExportOmitPDFON or IEPSExportPreferences::kExportOmitPDFOFF Printing Exporting to EPS and PDF z Omit for OPI: BitMap Images — IEPSExportPreferences::SetEPSExOmitBitmapImages, using IEPSExportPreferences::kExportOmitBitmapImagesON or IEPSExportPreferences::kExportOmitBitmapImagesOFF z Preset — IEPSExportPreferences::SetEPSExFlattenerStyle, using a UID of a kXPFlattenerStyleBoss object (use IFlattenerStyleListMgr to find one) z Ignore Spread Overrides — IEPSExportPreferences::SetEPSExIgnoreFlattenerSpreadOverrides, using IEPSExportPreferences::kExportIgnoreSpreadOverridesON or IEPSExportPreferences::kExportIgnoreSpreadOverridesOFF Exporting Using IK2ServiceRegistry, query for service providers supporting kExportProviderService. Find an export provider that can support the format name “EPS,” by iterating over all export providers and calling IExportProvider::CountFormats and IExportProvider::GetNthFormatName, or IExportProvider::CanExportThisFormat. Once you find the export provider for EPS, do the following: z Call IExportProvider::CanExportToFile to check whether the document and current selection target can be exported. z Optionally, query for IBoolData, set it to kTrue to set IPrintContentPrefs, and query for IPrintContentPrefs and call its Set methods. z Call IExportProvider::CanExportToFile or IExportProvider::ExportToStream to do the export. Exporting to PDF The structure of the PDF-export architecture is very similar to that of EPS export; however, you can specify a greater level of detail when exporting a document to PDF. For details of exporting to PDF, see the “PDF Import and Export” chapter. Printing 453 Printing Exporting to EPS and PDF 454 PDF Import and Export PDF import PDF Import and Export PDF import This section focuses on how you can control PDF import preferences during the PDF import process. Importing a file into InDesign requires a series of commands to be processed in a certain sequence. Before a PDF file can be imported, a page item needs to be created to hold the PDF content. Also, a proper datalink needs to be set up, so the association between the page item and the external file can be established. Figure 212 is a high-level illustration of the import process in InDesign for a standalone desktop PDF file (not a workgroup file) to be loaded into the place gun. The details of a complete import process is beyond the scope of this document. We recommend you always try to import (or place) a file using the method illustrated in the SnpPlaceFile.cpp snippet sample, which uses kImportAndPlaceCmdBoss to place the file on the active spread. You also can use kImportAndLoadPlaceGunCmdBoss to load the file into the place gun. Both commands check with all the import providers and pick the appropriate provider for the type of file to import. The PDF import provider (kPDFPlaceProviderBoss) is the default InDesign import provider for PDF files. kPDFPlaceProviderBoss processes kPDFPlaceCmdBoss, which is the central command that does the real work of importing a PDF file. PDF Import and Export 455 PDF Import and Export PDF import FIGURE 212 High-level view of importing a desktop PDF file fail succeed Receive an IDFile to import Import PDF Create a data link from the IDFile fail Open an IPMStream from the data link for import Delete the page item succeed Update user's PDF import pref based on the pref just used Add the data link to the page item Display PDF import option if necessary Release the datalink Release the datalink Create a new page item Make sure the page item is in a graphic frame Load the new item in the place gun When you import a PDF file through the InDesign Place dialog box, if you choose Show Import Options, the Place PDF dialog opens, as shown in Figure 213. The following options offer flexible PDF import: z 456 Placing multipage PDF pages (General tab) — You can place a range of PDF pages from a multipage PDF file. Under Pages, select All or enter a value for Range. The place gun is loaded as before, but the pointer changes to show that multiple pages exist. Each time you click, a PDF page is placed on the page. If you hold down the Alt/Option keys, the pointer changes to the cascade-place pointer, and clicking places all remaining pages on the page, cascading down from the click point. PDF Import and Export PDF import z Optional content groups (OCG) layers support (Layers tab) — OCG groups content for selective viewing and printing, supports complex mapping of objects to groups, and allows special use cases like language and zoom factors. By recognizing OCG constructs in placed PDF files, InDesign offers users the ability to selectively include those pieces of content. FIGURE 213 PDF import options General PDF import options are stored in the IPDFPlacePrefs interface, and layers options are stored in IGraphicLayerInfo; both interfaces are added to the kWorkspaceBoss workspace. Normally, these options are used unless the PDF import is performed through a link update; in that case, the IGraphicLayerInfo on the page item (kPlacedPDFItemBoss) is used instead, and some attributes from the IPDFAttributes aggregated on the kPlacedPDFItemBoss are used. The following attributes override the defaults under the condition of a link update: z IPDFAttributes::SetPage — Overrides PDF page number of the placed page. z IPDFAttributes::SetTransparentBackground — Overrides Transparency background. z IPDFAttributes::SetPreserveScreens — Overrides Preserve Halftone Screens. z IPDFAttributes::SetUserPassword — Overrides Set User Password. z IPDFAttributes::SetCropTo — Overrides Set Crop To. Figure 214 shows how kPDFPlaceProviderBoss sets up the data interfaces for kPDFPlaceCmdBoss in different cases. If the import is done with the full user interface, the user can change settings through the Place PDF dialog (see Figure 213). InDesign uses kPDFPlaceProviderBoss to do its PDF import, so by changing import options you control InDesign’s PDF import behavior. Figure 214 has a “Minimal UI” decision point. If the user deselects Show Import Options when importing a file, a minimal user interface is used: the user sees only a progress bar, not the Place PDF dialog. Figure 214 also has an “Is the PDF import for link update?” decision point. Link update is performed when the user selects Relink or Update from the Links panel. Doing this triggers a PDF import if the link is a PDF item. PDF Import and Export 457 PDF Import and Export PDF import FIGURE 214 kPDFPlaceProviderBoss import option use Is the import from clipboard? No Yes Get session prefs: IPDFPlacePrefs from IID_IPDFPLACEPREFS Get session prefs: IPDFPlacePrefs from IID_IPDFCLIPBOARDPLACEPREFS Process kPDFPlaceCmdBoss Get the session preference: IGraphicLayerInfo If the import was successful, and we are NOT importing from clipboard, and we are NOT in active INX context, then update the user’s PDF place preferences based on what they just chose using kSetPDFPlacePrefsCmdBoss Copy session preference data to kPDFPlaceCmdBoss data interface Is the PDF import for link update? Yes No Does the linked page item have IPDFAttributes Yes No Suppress UI? Yes No Override some session data with linked page item's IPDFAttributes Override the PDF password setting from the source PDF Minimal UI? Yes No Bring up PDF Import Dialog if available 458 PDF Import and Export PDF export The main interfaces to control the PDF import options are IPDFPlacePrefs, IGraphicLayerInfo, and IPDFAttributes. To modify the data stored in these interfaces, use the commands shown in Table 110. Note there is no command to modify the IPDFPlacePrefs for clipboard import (IID_IPDFCLIPBOARDPLACEPREFS). If you process your own kPDFPlaceCmdBoss, use the IPDFPlacePrefs aggregated on the command boss to set up the import option. The IGraphicLayerInfo on the page item passed to the kPDFPlaceCmdBoss is used for layer options. TABLE 110 Commands to Change PDF Import Options To change... Use IPDFPlacePrefs on the workspace kSetPDFPlacePrefsCmdBoss IGraphicLayerInfo on the workspace kSetPDFPlacePrefsCmdBoss IPDFAttributes on the page item kSetPDFAttributesCmdBoss IGraphicLayerInfo on the page item kSetGraphicLayerInfoCmdBoss PDF export InDesign/InCopy document export The easiest way to export an InDesign or InCopy document is to use the PDF export service provider. Example 27 is a snippet showing how to get the PDF export provider and call the export method. EXAMPLE 27 Getting the PDF export provider PMString PDFFormat("Adobe PDF"); PDFFormat.SetTranslatable(kFalse); InterfacePtr<ISelectionManager> selection(SelectionUtils::QueryActiveSelection()); IDocument *frontDoc = ::GetFrontDocument(); InterfacePtr<IK2ServiceRegistry> k2ServiceRegistry(gSession, UseDefaultIID()); // Look for all service providers with kExportProviderService. int32 exportProviderCount = k2ServiceRegistry>GetServiceProviderCount(kExportProviderService); // Iterate through them. bool found = kFalse; for (int32 exportProviderIndex = 0 ; exportProviderIndex < exportProviderCount ; exportProviderIndex++) PDF Import and Export 459 PDF Import and Export PDF export { // get the service provider boss class InterfacePtr<IK2ServiceProvider> k2ServiceProvider (k2ServiceRegistry->QueryNthServiceProvider(kExportProviderService, exportProviderIndex)); // Get the export provider implementation itself. InterfacePtr<IExportProvider> exportProvider(k2ServiceProvider, IID_IEXPORTPROVIDER); // Check to see if the current selection specifier can be exported by this provider. bool16 canExportByTarget = exportProvider->CanExportThisFormat(frontDoc, selection, PDFFormat); if (canExportByTarget) { found = kTrue; // assume idFile is a valid IDFile to hold the soon to be created PDF exportProvider->ExportToFile(idFile, frontDoc, selection, PDFFormat, kFullUI); } if (found) break; } In the example, note the following: z The format name used to get the PDF export provider is Adobe PDF, defined in the beginning of the example. z The example tells the PDF export provider to use the full user interface during the export, meaning the PDF export settings dialog is brought up for the user to set export options. The settings dialog box is provided by kPDFExportDialogBoss in InDesign and by kInCopyPDFExptDialogBoss in InCopy. They are selectable dialog service providers you can retrieve through the IK2ServiceRegistry::GetServiceProviderIndex method, although it is most practical to specify kFullUI and let the export provider do the work. If kSuppressUI is used instead, no user interface is presented, and you can change the preference as described below. z The example omits the steps that produce a valid IDFile to be passed into the IExportProvider::ExportToFile method. Normally, the IDFile is obtained through a standard Save File dialog box. You also can construct an IDFile from scratch. For more information on IDFile, see the “Using Adobe File Library” chapter. z The example is for exporting an InDesign/InCopy document. To export an InDesign book, see “InDesign book export” on page 468. The PDF export provider for InDesign/InCopy documents is represented by kPDFExportBoss. There is an IBoolData in kPDFExportBoss, which indicates whether print content preferences (IPrintContentPrefs) should be considered. When you export from the InDesign menu, the default value for the IBoolData is set to false, so no print content preference are used during the default PDF export. Also, the PDF export provider allows you to use an export style (kPDFExportStyleBoss) instead of dealing with the settings one by one. This is achieved by passing the style UID in the IUIDData aggregated on the kPDFExportBoss. The kPDFExportBoss processes kPDFExportCmdBoss. Before the command is processed, kExportValidationCmdBoss is used to verify that the attributes set for the command will pro- 460 PDF Import and Export PDF export duce a valid output. Table 111 summarizes the command interfaces kPDFExportBoss needs to set up before it processes kPDFExportCmdBoss. TABLE 111 Critical data interfaces for kPDFExportCmdBoss Interface Purpose IPDFExportPrefs Holds most of the PDF export settings as seen in the PDF export options dialog. IPDFSecurityPrefs Holds the PDF security preference. ISysFileData Holds the destination IDFile for the PDF document. IBoolData Indicates whether the IPrintContentPrefs should be used. IPrintContentPrefs Allows certain contents to be removed from the output. IBoolData (IID_IBOOKEXPORT) Indicates whether the command is used to export an InDesign book. IUIFlagData Tells the command to use kFullUI, kMinimalUI, or kSuppressUI. IOutputPages Holds the UIDs of the pages to output in layout mode. IInCopyGalleySettingData Data for galley export. IBoolData (IID_IINCOPYPDFNOTEANNOTATIONDATA) Layout export note annotation flag. From InDesign layout view If a style is passed to the export provider, the IPDFExportPrefs on the kPDFExportStyleBoss is copied to the IPDFExportPrefs on the kPDFExportCmdBos; otherwise, the IPDFExportPrefs on the kWorkspaceBoss is used. You can query the session’s PDF export preference as follows: InterfacePtr<IPDFExportPrefs> appExportPrefs((IPDFExportPrefs*)::QuerySessionPreferences(IID_IPDFEXPORTPREFS)); To change the preferences, process kSetPDFExportPrefsCmdBoss and use the Set*** methods of IPDFExportPrefs on the command boss to change the settings. IPDFSecurityPrefs is set up using the preferences saved in the session (i.e., IPDFSecurityPrefs on the kWorkspaceBoss). You can query the preferences as follows: InterfacePtr<IPDFSecurityPrefs> appSecurityPrefs((IPDFSecurityPrefs*)::QuerySessionPreferences(IID_IPDFSECURITYPREF S)); To change the security preferences, process kSetPDFSecurityPrefsCmdBoss and use the Set*** methods of IPDFSecurityPrefs on the command boss to change the settings. Another critical interface in kPDFExportCmdBoss that needs to be set up is IOutputPages. It holds the UIDs of the pages from the document for export. The PDF export provider uses IPageRange on the kWorkspaceBoss to initialize the IOutputPages on kPDFExportCmdBoss. kPDFExportDialogBoss uses the same data to initialize the export settings dialog user inter- PDF Import and Export 461 PDF Import and Export PDF export face, and it updates the session data when the user changes it from the dialog box. Example 28 shows how to set up IOutputPages from IPageRange on kWorkspaceBoss. EXAMPLE 28 Setting up kPDFExportCmdBoss’s IOutputPages from IPageRange InterfacePtr<IPageRange> myPageRange((IPageRange*)::QuerySessionPreferences(IID_IPAGERANGE)); IPageRange::RangeFormat pageRangeFormat = myPageRange->GetPageRangeFormat(); // Assume theDoc is a valid IDocument* for export. UIDList pageUIDs = UIDList(::GetDataBase(theDoc)); InterfacePtr<IPageList> iPageList((IPMUnknown*)theDoc, IID_IPAGELIST); if (pageRangeFormat != IPageRange::kAllPages) { PMString pageRange; pageRange = myPageRange->GetPageRange(); pageRange.SetTranslatable(kFalse); iPageList->PageRangeStringToUIDList(pageRange, &pageUIDs); } else { int32 cPages = iPageList->GetPageCount(); for (int32 iPage = 0; iPage < cPages; iPage++ ) { UID uidPage = iPageList->GetNthPageUID(iPage); pageUIDs.Append( uidPage ); } } // Assume pdfExportCmd is the valid ICommand* from kPDFExportCmdBoss. InterfacePtr<IOutputPages> iExportPages(pdfExportCmd, IID_IOUTPUTPAGES); // Assume exportPrefs is the previously set IPDFExportPrefs from kPDFExportCmdBoss. iExportPages->InitializeFrom(pageUIDs, (exportPrefs->GetPDFExReaderSpreads() == IPDFExportPrefs::kExportReaderSpreadsON)); PMString name; theDoc->GetName(name); iExportPages->SetName(name); From InCopy layout view There is an IInCopyPDFExptLayoutData interface on kWorkspaceBoss, which is used to store some InCopy layout export settings. During an InCopy layout export, IPDFExportPrefs is set up as described in “From InDesign layout view” on page 461. Then the IInCopyPDFExptLayoutData on the kWorkspaceBoss is used to override some of the data on the command’s IPDFExportPrefs. Table 112 summarizes the overrides. To change the IInCopyPDFExptLayoutData on the kWorkspaceBoss, use kSaveInCopyPDFExptLayoutDataCmdBoss. 462 PDF Import and Export PDF export TABLE 112 InCopy Layout-specific export settings Attributes Override Launch Adobe Acrobat Changed by SetPDFExLaunchAcrobat. If IInCopyPDFExptLayoutData::GetPDFExLaunchAcrobat is equal to kTrue, this is set to kExportLaunchAcrobatON; otherwise, kExportLaunchAcrobatOFF. Compatibility Level Changed by SetPDFExAcrobatCompatibilityLevel. Set to the value returned by IInCopyPDFExptLayoutData::GetPDFExAcrobatCompatibilityLevel. Compression Type Changed by SetCompressionType. If IInCopyPDFExptLayoutData::GetPDFExAcrobatCompatibilityLevel >= kPDFVersion15, this is set to kCompressObjects; otherwise, kCompressNone. Embed Page Thumbnails Changed by SetPDFExThumbnails. If IInCopyPDFExptLayoutData::GetPDFExThumbnails is equal to kTrue, this is set to kExportThumbnailsON; otherwise, kExportThumbnailsOFF. Optimize for Fast Web View Changed by SetPDFExLinearized. If IInCopyPDFExptLayoutData::GetPDFExLinearized is equal to kTrue, this is set to kExportLinearizedON; otherwise, kExportLinearizedOFF. Include Page Information Changed by SetPDFExPageInfo. If IInCopyPDFExptLayoutData::GetPDFExPageInfo is equal to kTrue, this is set to kExportPageInfoON; otherwise, kExportPageInfoOFF. Subset Fonts Threshold Changed by SetPDFExSubsetFontsThreshold. Set to the value returned by IInCopyPDFExptLayoutData::GetPDFExSubsetFontsThreshold. Export Reader Spreads Changed by SetPDFExReaderSpreads. If IInCopyPDFExptLayoutData::GetPDFExReaderSpreads is equal to kTrue, this is set to kExportReaderSpreadsON; otherwise, kExportReaderSpreadsOFF. Interactive Elements Changed by SetPDFExAddInteractiveElements. Set to the value returned by IInCopyPDFExptLayoutData::GetPDFExAddInteractiveElements. Multimedia Content to Embed Changed by SetContentToEmbed. Set to the value returned by IInCopyPDFExptLayoutData::GetContentToEmbed. IOutputPages for kPDFExportCmdBoss is set up like kPDFExportCmdBoss IOutputPages from IPageRange, except IInCopyPDFExptLayoutData::GetPDFExPageRangeFormat is used to check the range format and IInCopyPDFExptLayoutData::GetPDFExPageRange is used to get the range if the range format is not IInCopyPDFExptLayoutData::kAllPages. kPDFExportCmdBoss also aggregates an interface, IInCopyGalleySettingData. During InCopy layout export, IInCopyGalleySettingData::SetGalleySetting(kFalse) is called, so no IInCopyGalleySettingData is used. The IBoolData (IID_IINCOPYPDFNOTEANNOTATIONDATA) on the kPDFFxportCmdBoss is set to the value from IInCopyPDFExptLayoutData::GetPDFExAnnotationNotes. From InCopy story view or galley view Export from galley view is different than export from layout view, because the galley and story view on-screen may not be the export (print) view. Galley export allows the user to output the galley story with multiple columns and a selected range of story lines. When the user selects PDF Import and Export 463 PDF Import and Export PDF export export, a final view to the document is not yet available. The PDF export provider internally executes kCreatePrintGalleyViewCmdBoss to generate an invisible galley view for PDF port printing based on the user’s preferences. IInCopyPDFExptGalleyData on the kWorkspaceBoss is the default galley-specific setting data used during PDF export. It is used to set up some of the data in IPDFExportPrefs and IInCopyGalleySettingData; both are aggregated on kPDFExportCmdBoss. The PDF export provider does not take the data from IInCopyPDFExptGalleyData on the kWorkspaceBoss as is: if the galley document contains any story and the session’s IInCopyPDFExptGalleyData is default (checked through IInCopyPDFExptGalleyData::GetIsDefaultValues), the data shown in Table 113 is overridden. TABLE 113 IInCopyPDFExptGalleyData overrides when it is default 464 Attributes Override Font Leading Changed by SetPDFExFontLeading. Set to the string value returned from IGalleySettingsOverwrite::GetDisplayFontLeading. Font Name Changed by SetPDFExFont. Set to the value returned by Utils<IGalleyUtils>()>GetFontFamilyAndStyle. Font Size Changed by SetPDFExFontSize. Set to the string value returned from IGalleySettingsOverwrite::GetDisplayFontSize. Font Type Changed by SetPDFExFontType. Set to the value returned by Utils<IGalleyUtils>()>GetFontFamilyAndStyle. Include Accurate Line Endings Changed by SetPDFExALE. If ITextLine::GetLinesType is equal to ITextLines::kLayoutLineEnds, set to kTrue; otherwise, kFalse. Include Inline Notes Changed by SetPDFExInlineNotes. If there is at least one note anchor in the document, set to kTrue; otherwise, kFalse. Include Line Numbers Changed by SetPDFExLineNumber. Set to the value returned by Utils<IGalleyUtils>()>InGalley(). Include Paragraph Styles Changed by SetPDFExStyle. Set to the value returned from IGalleySettingsOverwrite::GetShowParagraphStyleNames. Include Track Changes Changed by SetPDFExTrackChanges. Set to the value returned from IGalleySettingsOverwrite::GetShowTrackChanges. Notes Type Changed by SetPDFExNotesType. Set to kVisible. Show Notes Backgrounds in Color Changed by SetPDFExNotesBackground. Set to kFalse. Show Track Changes Backgrounds in Color Changed by SetPDFExTrackChangesBackground. Set to kFalse. Track Changes Type Changed by SetPDFExTrackChangesType. Set to kVisible. PDF Import and Export PDF export NOTE: ITextLine and IGalleySettingsOverwrite should be from the galley view (kWritingModeWidgetBoss) of the exported document. In galley view mode, the PDF export provider initializes IPDFExportPrefs and IPDFExportPrefs in much the same way as described in “From InCopy layout view” on page 462, but the attributes from IPDFExportPrefs shown in Table 114 are overridden by IInCopyPDFExptGalleyData, as described above. TABLE 114 Galley-specific settings for IPDFExportPrefs Attributes Values Acrobat Compatibility Level Set by SetPDFExAcrobatCompatibilityLevel. Set to the value returned from IInCopyPDFExptGalleyData::GetPDFExAcrobatCompatibilityLevel. Include Page Information Set by SetPDFExPageInfo. If IInCopyPDFExptGalleyData::GetPDFExPageInfo is equal to kTrue, this is set to IPDFExportPrefs::kExportPageInfoON; otherwise, IPDFExportPrefs::kExportPageInfoOFF. Subset Fonts Threshold Set by SetPDFExSubsetFontsThreshold. Set to the value returned from IInCopyPDFExptGalleyData::GetPDFExSubsetFontsThreshold. As described in “From InCopy layout view” on page 462, IOutputPages is a critical interface that holds the UIDs of pages to be exported for kPDFExportCmdBoss in layout mode. For InCopy galley and story mode, however, IOutputPages cannot provide enough data for kPDFExportCmdBoss to draw a range of lines from galley view or rearrange the number of columns in the output PDF that are allowed in the galley export options dialog box. Therefore, the interface IInCopyGalleySettingData is aggregated on kPDFExportCmdBoss to hold the data used to create a galley window for PDF export. In addition to settings specific to galley mode, IInCopyGalleySettingData also holds the views (IControlView* of the galley writing widgets, paragraph information panel, etc.) that represent the real output pages based on the user’s galley export settings. kPDFExportCmdBoss passes these views to the PDF drawing port for output instead of using IOutputPages. The user of kPDFExportCmdBoss is responsible for setting up IInCopyGalleySettingData properly before the command is processed. The PDF export provider executes kCreatePrintGalleyViewCmdBoss to get an invisible output view based on the data from the current galley document and IInCopyPDFExptGalleyData. It then uses the view and IInCopyPDFExptGalleyData to set up IInCopyGalleySettingData for kPDFExportCmdBoss. The PDF export provider sets up IOutputPages of kPDFExportCmdBoss with IOutputPages returned from kCreatePrintGalleyViewCmdBoss, which has the values shown in Table 115. PDF Import and Export 465 PDF Import and Export PDF export TABLE 115 IOutput pages from kCreatePrintGalleyViewCmdBoss Attributes Values ContiguousPages kTrue Name Name of the galley document IsSpreads kFalse MasterDataBase Database for the window created by the kCreatePrintGalleyViewCmdBoss UIDs Placeholder. UIDs number from 0 to total pages-1. UIDs contained in IOutputPages are not used by kPDFExportCmdBoss in InCopy galley and story mode. The following steps summarize how the PDF export provider sets up IInCopyGalleySettingData for kPDFExportCmdBoss. 1. A new kInCopyGalleySettingDataBoss is created, with default value. 2. IInCopyPDFExptGalleyData is used to override the IInCopyGalleySettingData of the new kInCopyGalleySettingDataBoss. 3. IInCopyGalleySettingData is used to execute the kCreatePrintGalleyViewCmdBoss command. 4. A copy of IInCopyGalleySettingData returned from kCreatePrintGalleyViewCmdBoss in Step 3 is used to set up kPDFExportCmdBoss. Table 116 shows how attributes from IInCopyGalleySettingData get their values in different stages. In the table, “PEGD” stands for IInCopyPDFExptGalleyData from Step 2 above. TABLE 116 Setting up IInCopyGalleySettingData for kPDFExportCmdBoss 466 Attribute and description Default value Overridden value Final value after kCreatePrintGalleyViewCmdBoss Galley/story control view nil nil Calculated by kCreatePrintGalleyViewCmd Boss Paragraph panel control view (GetInfoColumnView) nil nil Calculated by kCreatePrintGalleyViewCmd Boss Line number panel control view (GetLineNumberView) N/A, not used N/A, not used N/A, not used Splitter control view (GetInfoSplitterView) nil nil Calculated by kCreatePrintGalleyViewCmd Boss PDF Import and Export PDF export Attribute and description Default value Overridden value Final value after kCreatePrintGalleyViewCmdBoss Total content height of the galley (GetTotalHeight) 0 0 Calculated by kCreatePrintGalleyViewCmd Boss Start Line Number (GetStartLineNumber) N/A, not used N/A, not used N/A, not used End Line Number (GetEndLineNumber) N/A, not used N/A, not used N/A, not used Column width (GetColumnWidth) 0 Calculated based on PEGD and current unit settings Calculated by kCreatePrintGalleyViewCmd Boss GalleySetting kTrue kTrue kTrue Document UIDRef (GetDocUIDRef) N/A UIDRef of galley document UIDRef of galley document To print with paragraph style info (GetParaStyle) kFalse from PEGD from PEGD To print with line number (GetLineNumber) kFalse from PEGD from PEGD To print with accurate line ending (GetALE) kFalse from PEGD from PEGD To print with notes displayed (GetNotes) kFalse from PEGD from PEGD To print with tracked changes displayed (GetTrackChange) kFalse from PEGD from PEGD Notes displayed type (GetNotesType) kVisible from PEGD from PEGD Track change displayed type (GetTrackChangesType) kVisible from PEGD from PEGD Font name (GetFontName) “” from PEGD from PEGD Font type (GetFontType) “” from PEGD from PEGD Font size (GetFontSize) “” from PEGD from PEGD Font leading (GetFontLeading) “” from PEGD from PEGD PDF Import and Export 467 PDF Import and Export PDF export Attribute and description Default value Overridden value Final value after kCreatePrintGalleyViewCmdBoss To print with line range scope (GetWhich) IIncopyGalley PrintData::kAll If PEGD’s GetPDFExlineRangeFormat is IInCopyPDFExptGalleyDat a::kAllLine, set to kAllLines; otherwise, kUseRange If PEGD’s GetPDFExlineRangeFormat is IInCopyPDFExptGalleyData: :kAllLine, set to kAllLines; otherwise kUseRange. To print the line range (GetRange) “” from PEGD from PEGD Galley frame size (GetFrameSize) Rect(0, 0, 0, 0) Set frame to the page bounds from the first page of the galley document. Set frame to the page bounds from the first page of the galley document. To print with content filled with the page (GetFill) kFalse If GetALE returns true, then set to the return value from PEGD’s GetPDFExFill; otherwise, kFalse. If GetALE returns true, then set to the return value from PEGD’s GetPDFExFill; otherwise, kFalse. Story range (GetScope) IInCopyGalley PrintData::kAll from PEGD from PEGD To print with story information (GetStoryInfo) kFalse from PEGD from PEGD To print with notes background in color (GetNotesBackgroundInColor) kTrue from PEGD from PEGD To print with track changes background in color (GetTrackChangesBackgroundI nColor) kTrue from PEGD from PEGD To print with page information (GetPagesInfo) kFalse kFalse kFalse (kPDFExportCmdBoss takes this info from IPDFExportPrefs) To print with number of columns (GetColumns) 1 1 Calculated by kCreatePrintGalleyViewCmd Boss InDesign book export You can use the high-level kBookExportActionCmdBoss to easily export a book. For details, see SnpExportBookAsPDF.cpp. kBookExportActionCmdBoss uses kPDFExportBookBoss (with service ID kExportBookService), which uses the same PDF export service provider (kPDFExportProviderImpl) as the 468 PDF Import and Export PDF export kPDFExportBoss; however, kPDFExportBookBoss aggregates an IOutputPages interface that lists document pages in the book to export. The regular document kPDFExportBoss does not aggregate IOutputPages; it sets up IOutputPages for the kPDFExportCmdBoss based on the IPageRange, as shown in Example 28. Selected page-items export There is no direct user interface to allow export of selected page items in InDesign; however, you can copy selected page items to the pasteboard in PDF format. Then, when you paste into an external application that supports PDF import, the pasted object is in PDF format. This is done through kPDFExportItemsCmdBoss. The snippet in Example 29 shows how to process the command. EXAMPLE 29 How to process a kPDFExportItemsCmdBoss command // Assume stream is the destination PDF file write stream. // Assume realPageItems contains no guide item, which can // cause trouble in PDF export. InterfacePtr<ICommand> command(CmdUtils::CreateCommand(kPDFExportItemsCmdBoss)); if (command) { command->SetItemList(realPageItems); // Initialize the command data from the session. InterfacePtr<IPDFExportPrefs> appExportPrefs((IPDFExportPrefs *) ::QuerySessionPreferences(IID_IPDFCLIPBOARDEXPORTPREFS)); InterfacePtr<IPDFExportPrefs> exportPrefs(command, IID_IPDFEXPORTPREFS); InterfacePtr<IPDFSecurityPrefs> appSecurityPrefs((IPDFSecurityPrefs *) ::QuerySessionPreferences(IID_IPDFSECURITYPREFS)); InterfacePtr<IPDFSecurityPrefs> exportSecurityPrefs(command,IID_IPDFSECURITYPREFS); exportPrefs->CopyPrefs(appExportPrefs); exportSecurityPrefs->CopyPrefs(appSecurityPrefs); // no progress bar InterfacePtr<IBoolData> useProgressBar(command, IID_IUSEPROGRESSINDICATOR); useProgressBar->Set(kFalse); InterfacePtr<IUIFlagData> uiFlagData(command, IID_IUIFLAGDATA); uiFlagData->Set(kSuppressUI); // Assume no destination color profile (i.e., ignore IUIDData). // (IID_IPDFDESTCMSPROFILE) // Put the stream pointer in the IIntData. InterfacePtr<IIntData> exportCmdStreamData(command, IID_IINTDATA); exportCmdStreamData->Set((long) stream); // process the command CmdUtils::ProcessCommand(command); success = ErrorUtils::PMGetGlobalErrorCode(); } PDF Import and Export 469 PDF Import and Export PDF-style import and export PDF-style import and export When the PDF export provider brings up the Export Adobe PDF options dialog box, the dialog box is initialized according to the following rules: 1. A preset style UID may be passed in. When it is available, use it. 2. Otherwise, if the last preset used is named “[Custom]” or the style name ends with “(modified),” use the application preferences of the workspace. 3. Otherwise, if the last preset used is not empty and is valid, use it. 4. Otherwise, use the default preferences. This is the first time the export dialog is run after deleting Save Data. PDF export style is represented by kPDFExportStyleBoss, which aggregates an IPDFExportPrefs interface that stores the settings. Usually, the IPDFExportPrefs -> CopyPrefs method is used to copy the setting out of the style boss to another IPDFExportPrefs you are using. The last preset style’s name is saved in the IPDFExportStyleLastUsed on the kWorkspace. You can use the snippet in Example 30 to get the name in PMString: EXAMPLE 30 Getting the last-used style name InterfacePtr<IPDFExportStyleLastUsed> iStyleLast((IPDFExportStyleLastUsed*)::QuerySessionPreferences (IID_IPDFEXPORTSTYLELASTUSED)); PMString lastPreset; if (iStyleLast) lastPreset = iStyleLast->GetString(); lastPreset.SetTranslatable(false); Given a style name, you can use IPDFExptStyleListMgr (aggregated on kWorkspace) to obtain the UID style object, Continuing from Example 30, Example 31 shows how to get to a last used style object from its name: EXAMPLE 31 Getting a style object using name InterfacePtr<IPDFExptStyleListMgr> styleMgr((IPDFExptStyleListMgr*)::QuerySessionPreferences(IID_IPDFEXPORTSTYLELISTMG R)); int32 nStyle = styleMgr->GetStyleIndexByName(lastPreset); if (nStyle != -1) { UIDRef styleRef = styleMgr->GetNthStyleRef(nStyle); InterfacePtr<IPDFExportPrefs> pStylePrefs(styleRef, UseDefaultIID()); if( pStylePrefs ) { // assume myExportPrefs is an IPDFExportPrefs I am trying to set up myExportPrefs->CopyPrefs(pStylePrefs); }; } 470 PDF Import and Export PDF-style import and export Adding, deleting, and editing styles To add a style, use kPDFExportAddStyleCmdBoss. Example 32 shows how to process the command: EXAMPLE 32 Adding a PDF-export style InterfacePtr<ICommand> addCmd(CmdUtils::CreateCommand(kPDFExportAddStyleCmdBoss)); InterfacePtr<IExportStyleCmdData> cmdData(addCmd, IID_IEXPORTSTYLECMDDATA); InterfacePtr<IWorkspace> workspace(gSession->QueryWorkspace()); UIDRef workspaceUIDRef = ::GetUIDRef(workspace); cmdData->SetSrcList(workspaceUIDRef); cmdData->SetDstList(workspaceUIDRef); // Assume presetName is a PMString containing the new style name. cmdData->SetNewName(presetName); cmdData->SetStyleIndex(-2); // -2 means get the PDF preferences from the command. InterfacePtr<IPDFExportPrefs> commandPrefs(cmdData, UseDefaultIID()); // Assume pSrcPref is my source IPDFExportPrefs to be made into the new style. commandPrefs->CopyPrefs(pSrcPrefs); commandPrefs->SetUIName(presetName); ErrorCode rc = CmdUtils::ProcessCommand(addCmd); The command boss aggregates an IExportStyleCmdData that has a method, SetStyleIndex, that sets up a style index for the command. The style index tells the command where the source style comes from, according to the following rules: 1. If there is valid index (index >= 0), that style's PDF preferences (queried from an IPDFExptStyleListMgr returned by IExportStyleCmdData::GetSrcList) are used. 2. If the index is -2, the PDF preferences come from the command. 3. If the index is -3, the PDF preferences come from the command, but the data is not written to disk. 4. Otherwise, the PDF preferences come from the current application preferences. 5. In all cases except -3, the data is written to disk. To delete a style, use kPDFExportDeleteStyleCmdBoss. Example 33 shows how to delete a style stored in the application’s workspace: EXAMPLE 33 Deleting a PDF-export style InterfacePtr<IWorkspace> workspace(gSession->QueryWorkspace()); UIDRef workspaceUIDRef = ::GetUIDRef(workspace); InterfacePtr<ICommand> deleteCmd(CmdUtils::CreateCommand(kPDFExportDeleteStyleCmdBoss)); InterfacePtr<IExportStyleCmdData> commandData(deleteCmd, IID_IEXPORTSTYLECMDDATA); // Assume i is the (to-be-deleted) style index in the style list. commandData->SetStyleIndex(i); commandData->SetDstList(workspaceUIDRef); CmdUtils::ProcessCommand(deleteCmd); PDF Import and Export 471 PDF Import and Export Frequently asked questions To edit a style, use kPDFEditStyleCmdBoss. Example 34 shows how to edit a style stored in the application’s workspace: EXAMPLE 34 Editing a PDF style InterfacePtr<ICommand> editStyleCmd(CmdUtils::CreateCommand(kPDFEditStyleCmdBoss)); InterfacePtr<IIntData> data(editStyleCmd, IID_IINTDATA); // Assume index is the index of the style to be edited. data->Set(index); InterfacePtr<IPDFExportPrefs> newPrefs(editStyleCmd, IID_IPDFEXPORTPREFS ); // Assume myPrefs is the edited copy of IPDFExportPrefs. newPrefs->CopyPrefs(myPrefs); CmdUtils::ProcessCommand(editStyleCmd); Frequently asked questions How does the PDF export provider determine whether it should start the viewer after the export? In InDesign, IPDFPostProcessPrefs is used to maintain persistent PDF preference data not part of the standard IPDFExportPrefs. IPDFPostProcessPrefs is aggregated on kWorkspaceBoss and can be queried through QuerySessionPreferences. Use IPDFPostProcessPrefs::GetViewAfterExport to determine whether the viewer should be launched. In InCopy, IInCopyPDFExptGalleyData::GetPDFExLaunchAcrobat (for galley) and IInCopyPDFExptLayoutData::GetPDFExLaunchAcrobat (for layout) are used to determine whether the viewer should be started. How do I set the PDF clipboard setting as seen in the File Handling preferences? Those settings (e.g., Prefer PDF when Pasting) are kept in the IPDFClipboardPrefs aggregated on the kWorkspaceBoss. To modify the settings, use kSetPDFCBPrefsCmdBoss. How do I control which layer of a document should be exported? IPDFExportPrefs::SetExportLayers can be used to control the function of layers for visibility and printability. Use the enums kExportAllLayers, kExportVisibleLayers, and kExportVisiblePrintableLayers to set the export layer’s preference. Each layer’s visibility and printability are controlled by each layer’s option, managed by IDocumentLayer. For more information about how to set each layer’s visibility and printability, see the “Layer Options” section of the “Layout Fundamentals” chapter. 472 PDF Import and Export Frequently asked questions How do I make the two-page spreads in my document export as two separate PDF pages? Set the Boolean control for reader spreads in the IPDFExportPrefs to false. The IOutputPages on the kPDFExportCmdBoss usually is initialized as follows: InterfacePtr<IOutputPages> iExportPages(cmd, IID_IOUTPUTPAGES); iExportPages->InitializeFrom(pageUIDs, (exportPrefs->GetPDFExReaderSpreads() == IPDFExportPrefs::kExportReaderSpreadsON)); If the preference for the reader spreads is set to false and you set up IOutputPages as above, the two pages spreads are exported as separated pages in the PDF. See “Setting up kPDFExportCmdBoss’s IOutputPages from IPageRange” on page 462. Why does kPDFExportCmdBoss give me an assert after the command is processed (ASSERT 'db != nil' in PDFExportController.cpp)? Make sure you put the UIDRef of the pages in the IOutputPage interface. Also, set the item list with the pages’ UIDRef values (in a UIDList). kPDFExportCmdBoss is used for exporting both books (multiple .indd files) and multiple pages from a document. kPDFExportCmdBoss first checks to see whether it has a valid IOutputPages and uses the database from the first UIDRef of the output pages. If the command cannot find a valid database from IOutputPages, it looks for it from the command item list. How do I set up line ranges for output in InCopy Galley or Story mode? Use IInCopyPDFExptGalleyData::SetPDFExLineRange. Pass in a PMString with a format like “3-10” (i.e., the beginning page number, followed by a dash, followed by the ending page number). IInCopyPDFExptGalleyData is aggregated on the kWorkspaceBoss. Is it possible to export only selected text from an InDesign document? No. When printing or exporting to PDF, the decision to draw or not draw is made at the pageitem level. This is evidenced by the “Nonprinting” attribute, which can be applied to a text frame but not the text itself. Similarly, draw event handlers work on the page-item level, such as the text frame. PDF Import and Export 473 PDF Import and Export Frequently asked questions 474 Implementing Preflight Rules Introduction Implementing Preflight Rules Introduction This chapter provides high-level information for developers who want to build their own rules or set of rules. It complements the low-level information found in the SDK. About preflight in InDesign CS4 InDesign CS4 has a new feature for profile-based preflight. There was a preflight feature before CS4, but it was designed primarily for improving the reliability of the package operation. CS4 includes a fully rule-driven, parameterized, continuous preflight that can run in the background as you work. The preflight model comprises several major areas, most of which are fully extensible by external developers. Very little preflight code is written using private interfaces. z The preflight object model is a parallel view of the InDesign document and things that do not appear in the document. It has references to both standard InDesign objects like page items and documents and to non-persistent entities like marking operations. The object model is fully extensible to support new objects. z Preflight rule services are where objects are checked for compliance with a set of parameters. A rule provides discovery, visitation, and reporting functions to the preflight engine. z Preflight processes are idle-task-driven in-memory objects which coordinate all interactions between the object model and the rule services. Processes also can be driven synchronously if desired, but normally they run in the background. The processes are not extensible, but developers have full access to their status and database. This chapter is concerned only with the rule services, which are the most common type of extension. About rules In the preflight model, rules are the entities that check conditions in the document and generate errors. An example of a rule is “Missing and Modified Graphics,” which looks for graphics that are missing or outdated. Implementing Preflight Rules 475 Implementing Preflight Rules Rule IDs To write a rule, you need two things: z The rule boss encapsulates both the intelligence and data for a rule. z The rule service tells InDesign that your rule exists and lets it create a boss for a rule. A rule service can “host” as many rules as desired; the native InDesign rule service hosts dozens of rules. Rule IDs Each unique rule (for example, missing fonts or image resolution) is identified by a rule ID. A rule ID is simply a WideString that is never exposed in the user interface but serves to distinguish it from every other rule out there. For each rule you implement, you need to devise a unique rule ID. For example, you could prefix your rule ID with your company name or use a GUID converted to a string. Rule IDs are exposed to scripting. Rule service A rule service is implemented as a standard InDesign service with the service ID kPreflightRuleService. On the service boss, you need the IID_IK2SERVICEPROVIDER (you can use kPreflightRuleSPImpl for the implementation) and an IPreflightRuleService. The latter interface has two methods, shown in Table 117. TABLE 117 Methods in your IPreflightRuleService implementation Method Purpose GetAllRules Returns a vector of rule IDs that your services hosts. CreateRule Given a rule ID that you host, creates a rule boss and returns it. In other words, this interface provides a map and boss factory for rule bosses. Most of the complexity is in the rule bosses themselves. CreateRule can be called on when InDesign is creating new preflight profiles or, in some cases, for purely temporary purposes. For example, it might create a rule just to get some information about it, then destroy it. It takes a database pointer to indicate whether it wants the boss to be created in a document (or preferences) or in memory for temporary purposes. 476 Implementing Preflight Rules Rule service IPreflightRuleService example To illustrate a typical rule-service implementation, here are some sample method implementations. In this example, there are two rules, Maximum Text Size and Maximum Rectangle Size. IPreflightRuleService::GetAllRules The first step is to create rule IDs for these rules; typically, we’ll also need rule bosses. If XYZCo company is developing the rules, we might use the mapping shown in Table 118. TABLE 118 Mappings used in our PreflightRuleService example Rule Rule ID Boss Maximum text size XYZCo_MaxTextSize kMaxTextSizeRuleBoss Maximum rectangle size XYZCo_MaxRectSize kMaxRectSizeRuleBoss The GetAllRules method must return a vector of rule IDs. This is not complicated: const PreflightRuleID kMaxTextSizeRuleID("XYZCo_MaxTextSize"); const PreflightRuleID kMaxRectSizeRuleID("XYZCo_MaxRectSize"); virtual PreflightRuleIDVector GetAllRules() const { PreflightRuleIDVector rules; rules.push_back(kMaxTextSizeRuleID); rules.push_back(kMaxRectSizeRuleID); return rules; } This method usually will be called only once per session, by the rule manager, which then holds onto the information in its internal maps. IPreflightRuleService::CreateRule This method creates the appropriate boss from a passed-in rule ID and fills in defaults. In our example, we would do something like the following. (For ease of reading, most error handling is omitted.) virtual IPreflightRuleInfo* CreateRule ( // Rule to create PreflightRuleID ruleID, // Database in which to create it (nil = in memory) IDataBase* db ) const { ClassID bossID = 0; PMString desc; if (ruleID == kMaxTextSizeRuleID) { bossID = kMaxTextSizeRuleBoss; desc = PMString("Maximum text size"); } Implementing Preflight Rules 477 Implementing Preflight Rules Rule bosses else if (ruleID == kMaxTextSizeRuleID) { bossID = kMaxRectSizeRuleBoss; desc = PMString("Maximum rectangle size"); } else return nil; IPreflightRuleInfo* iRule = (IPreflightRuleInfo*)CreateObject (db, bossID, IID_IPREFLIGHTRULEINFO); iRule->SetRuleID(ruleID); iRule->SetRuleDescription(desc); iRule->SetPluginDescription("XYZCo Rules Plugin"); // Set up default parameter values. InterfacePtr<IPreflightRuleUtilities> iUtils(iRule, UseDefaultIID()); iUtils->UpdateRuleData(); return iRule; } It is up to you what strategy to use for initialization, mapping rule IDs to bosses and descriptions, and so on. If you have only a few rules, the method above should suffice. Rule bosses A rule boss is where all the heavy lifting goes on in the preflight world. A rule boss corresponds to a particular rule and encapsulates all the behaviors of that rule, including the following: z Parameter data — For example, if your rule looks for things larger than X, and the user can specify X, X is a rule parameter. z User interface — This is the interface used to modify your rule parameters. z Evaluation — Your rule is a visitor. The preflight engine “carries it around” to objects it wants to visit, and the rule must determine if the object is alright or has an error. z Aggregation — Once your rule finishes gathering errors, it must determine how to present the errors to the user. z Utilities — If your rule has any special requirements when copied or deleted, it needs to provide those implementations. As shown in the previous example, each rule your plug-in supports typically has its own boss. Each rule boss must have the interfaces shown in Table 119. You can add whatever other interfaces you want on your rule bosses. 478 Implementing Preflight Rules Rule bosses TABLE 119 Required interfaces on rule bosses Interface Purpose IPreflightRuleData Stores the rule parameter data as a dictionary (key-value pairs). Use kPreflightRuleDataImpl unless you have a really good reason not to do so. IPreflightRuleVisitor Provides all the evaluation and aggregation functions. This interface tells InDesign what kinds of objects the rule wants to visit (page items, styles, artwork, etc.), is called back when it is time to visit one of those objects, and is called back when it is time to aggregate (create final report of findings). Also, it provides some parameter initialization and validation methods. IPreflightRuleUtilities Provides rule-specific utilities for your rule, including copying the rule, any special deletion requirements, and determining equality with other rules. In most cases, you can use the default kPreflightRuleUtilitiesImpl implementation. These interfaces are documented in the headers and doc++ comments, but the IPreflightRuleVisitor interface is critical, so we expand on it below. IPreflightRuleVisitor interface The IPreflightRuleVisitor interface has three methods related to rule evaluation, shown in Table 120. TABLE 120 Rule evaluation methods on IPreflightRuleVisitor Method Description GetClassesToVisit Preflight calls this method, generally on start-up, when it builds its maps relating rules to objects. It must return a vector of preflight object class IDs that your rule wants to visit. For example, if you want to visit all images, you would return a vector containing kPreflightOM_Image. Visit Preflight calls this method when it is time to evaluate a given object, either because it was not visited before or something was changed such that the result might be different. This method is passed an abstract utility class that your method uses to obtain information and report its findings. AggregateResults Preflight calls this method after the first pass (visitation) is complete and the Visit method found something it might want to report. This method takes the “raw” results found during visitation into final presentation, in the form of nodes in the results tree. This method typically consolidates multiple errors into a single node, builds strings, and so on. Implementing Preflight Rules 479 Implementing Preflight Rules IPreflightRuleVisitor method examples The IPreflightRuleVisitor interface also has two methods related to rule-parameter initialization and validation, shown in Table 121. (These could be on another interface but since every rule needs to implement them, there is less overhead to include them on this interface, since every rule needs its own IPreflightRuleVisitor.) TABLE 121 Parameter methods on IPreflightRuleVisitor Method Description UpdateRuleData Preflight calls this method at start-up (for application profiles) and document open time (for document embedded profiles), to give the rule an opportunity to initialize and/or update the rule parameters. ValidateRuleData Preflight calls this method when a parameter is set via scripting, to ensure it is a legitimate value. IPreflightRuleVisitor method examples The methods in this interface concentrate on the discovery, visitation, and aggregation phases of the preflight process. This is the trickiest interface to write. IPreflightRuleVisitor::GetClassesToVisit This method simply tells InDesign what object classes your rule wants to visit. For example the missing-fonts rule looks at text runs (to see directly which fonts are used and where), as well as placed content that has required-font data, namely placed EPS, EPS, and INDD files. Its implementation looks like the following: virtual PreflightObjectClassIDVector GetClassesToVisit() const { PreflightObjectClassIDVector classes; classes.push_back(kPreflightOM_WaxRun); classes.push_back(kPreflightOM_EPS); classes.push_back(kPreflightOM_PDF); classes.push_back(kPreflightOM_INDD); return classes; } Do not declare classes in which you are not actually interested. The preflight engine expands only those portions of the model required to satisfy the rules in the profile, If you ask for artwork, for instance, you will take a big hit in processing cycles; do this only if it is needed. 480 Implementing Preflight Rules IPreflightRuleVisitor method examples IPreflightRuleVisitor::Visit This is the method in which your rule inspects objects it asked to visit. Typically, this method consists of comparing attributes of the object against rule parameters. The argument for this method is a IPreflightVisitInfo interface, which provides all the information you should need about the object being visited. It also provides the mechanism for reporting the errors. Table 122 lists the methods in this interface. TABLE 122 IPreflightVisitInfo methods Method Purpose QueryOptions Gets the IPreflightOptions interface for the current process. Not typically used, but sometimes rules want to know the options. GetObjectID Gets the PreflightObjectID of the thing being visited. Typically, this is used to get the ClassID of that object, if your rule looks at multiple object types. QueryObject Obtains the IPreflightObject interface for the object being visited. This is used in nearly every rule, because it lets you ask questions about the object. CreateResultRecord Creates a result record; that is, records a problem (or potential problem) with this node. Usually, this is an error indication, but not necessarily; you might use this to count instances of something and have an error only if it finds more than a certain number. Here is an example of a Visit implementation, the page-count rule. (To enhance readability, most error checking, like nil interfaces, is omitted.) virtual void Visit(IPreflightVisitInfo* iVisit) override { InterfacePtr<IPreflightObject> iObj(iVisit->QueryObject()); InterfacePtr<IDocument> iDoc(iObj->GetModelRef(), UseDefaultIID()); InterfacePtr<IPageList> iDocPages(iDoc, UseDefaultIID()); int32 count = iDocPages->GetPageCount(); PreflightRuleDataHelper dh(this); ComparisonType comp = (ComparisonType)dh.GetIntParam (kParamCountComparisonType); int32 value = dh.GetIntParam(kParamCountComparisonValue); int32 value2 = dh.GetIntParam(kParamCountComparisonValue2); bool32 fails = kFalse; Implementing Preflight Rules 481 Implementing Preflight Rules IPreflightRuleVisitor method examples switch(comp) { case kComparison_EqualTo: fails = (count != value); break; case kComparison_Minimum: fails = (count < value); break; case kComparison_Maximum: fails = (count > value); break; case kComparison_MultipleOf: fails = value > 1 && (count % value != 0); break; case kComparison_Between: fails = (count < value || count > value2); break; } if (fails) { InterfacePtr<IPreflightResultRecord> iRec (iVisit->CreateResultRecord()); iRec->SetCriteria(kPreflightRC_Default); iRec->AddValue(count); } } In this case, the rule is looking only at the document object, so it does not need to check for the class ID of the object that is passed in. The first thing it does is as follows: InterfacePtr<IPreflightObject> iObj(iVisit->QueryObject()); InterfacePtr<IDocument> iDoc(iObj->GetModelRef(), UseDefaultIID()); Since the object in question is the document, it has a model mapping, so iObj->GetModelRef() produces the UIDRef of the document. Not all objects have a model mapping. You need to do things that are unique to the kind of object you are looking at, even if in general those things fall into general categories. The rest of the implementation simply compares the number of pages against the rule parameter, using the rule’s comparison type (also a rule parameter). If it fails, then it does the following: InterfacePtr<IPreflightResultRecord> iRec (iVisit->CreateResultRecord()); iRec->SetCriteria(kPreflightRC_Default); iRec->AddValue(count); This code creates a result record, which is simply a small data structure that records what the rule tells it to, and attaches it in the process database (a non-persistent database) to the node representing the object (in this case, the document). This record can be produced later (along with all other records the rule created as it inspected objects), in the results-aggregation method. In this example, there is only one object, the document, but in a case where you are inspecting page items or marking operations, there could be dozens or hundreds. 482 Implementing Preflight Rules IPreflightRuleVisitor method examples After the result record is created, the rule sets the criteria to kPreflightRC_Default. This is the value used by rules that do not need to break down errors into different categories (or at least not at the time it is finding the errors). Finally, consider the case where the rule is adding a value to the record. The meaning of this value and the use of the value vector are completely up to the rule; however, when the rule is inspecting the object, it may make complex decisions or get calculated values that are inconvenient to repeat when results are aggregated. For example, a marking operation that looks at stroke width will record the stroke width it found, because it does not want to have to look it up again later. More examples of this are later in this section. Table 123 shows the contents of a results record. TABLE 123 Contents of a result record Field Uses Object ID The PreflightObjectID of the entity to which the record refers. This always is the object to which the record was attached. Subparts A vector of subpart IDs. Normally, this is set up by one of the aggregation utilities during the aggregation phase, but a rule also may specify a subpart, if that is useful. Values A vector of PMReals. Normally, this is a width, height, or other quantity you want to record for this instance. For example, you can record the width of a stroke you found. The aggregation utilities also use this information when combining multiple records together. Criteria This can be used to differentiate different kinds of failure. This field also is used by the aggregation utilities to simplify the process of generating results. An example is the image-resolution rule, which has different criteria for each image type and min/max failure. This means that the aggregation method does not have to determine what the image type was again. Aux String This is just string data that the rule can use as it wishes. For example, the font-type rule records the font name here. This allows it to build results easily, because the aggregation utilities can sort by this value. Process Node If this record was created by IPreflightVisitInfo::CreateResultRecord, it has the process node ID recorded here. This is useful if you want to look at the result relative to other objects in the tree. The aggregation utilities use this to determine the relationship between artwork and containing objects. IPreflightRuleVisitor::AggregateResults This method is where your rule takes the results (specifically, the result records) found in the Visit phase and produces nodes in the aggregated results tree. In other words, the input is the array of result records; for example: Implementing Preflight Rules 483 Implementing Preflight Rules IPreflightRuleVisitor method examples Stroke on object X is 0.1 pt Stroke on object Y is 0.1 pt The output is a hierarchy of preflight aggregated result nodes; for example: Strokes are too small Object X Object Y This example is simple. In the general case, especially with artwork, the raw results can be numerous, with many grouped under the same object (e.g., the same PDF). The tree contains several different kinds of nodes: z Category nodes are added by the preflight engine and represent the rule categories; for example, Document, Links, and Text. These nodes are created automatically by preflight, based on the categories the rule services declare and place the rules in. z Criteria nodes are used to group failing objects together under the common failure type. For example, “Strokes are too small” is a criteria, under which you would put the violations of that rule (Object X and Object Y, in the above example). z Violation nodes are individual failures of a rule. In the example above, “Object X” and “Object Y” are violation nodes. z Criteria/violation nodes are nodes that are both criteria and violation, because there is only a single object or single failure for that rule. Typically, this means it is a document-level error, like number of pages. Each node has a short string that appears in the tree-view widget in the preflight panel and long-form strings that appear in the Info section. In both cases, these strings also appear in the preflight report. Mapping the raw preflight result records to the tree hierarchy can be complex, because each rule usually has its own strategy for reducing the complexity of the results presentation. The preflight API allows the rules to do this any way they like, but it supports those mechanisms with utilities that reduce the line count. All these utilities are in IPreflightAggregatedResultsUtils. The recommended sequence of events in the AggregateResults method is as follows. The code assumes a declaration with the following arguments: virtual void AggregateResults ( const IPreflightProcess* iProcess, const IPreflightProcess::NodeIDVector& resultNodes, IPreflightAggregatedResults* iResults, IPreflightAggregatedResults::NodeID parentID ) const The first two parameters can be thought of as the inputs to the aggregation process; i.e., the nodes in the process database corresponding to the raw results found during the Visit. The last two parameters can be thought of as the outputs: iResults is the artwork-tree interface you would use to add nodes, and parentID is the node in that tree under which you should add your nodes as children. 484 Implementing Preflight Rules IPreflightRuleVisitor method examples All utilities in the IPreflightAggregatedResultsUtils work on preflight result records, collecting them in tables (IPreflightResultRecordTable) for most operations. A IPreflightResultRecordTable is simply a vector of ref-counted record pointers, so dividing a table into subtables is a fairly quick operation; therefore, most of the utilities transform one table of results into another, at which point those results are copied into the aggregated results tree. Typical steps in aggregation are as follows: 1. Get the raw table of results — All the rule’s result records are extracted from the process database, to get an initial, raw, unprocessed table. 2. Apply standard aggregations — Records are combined in the table using standard combination techniques, such as localizing artwork to the page items that contain it and combining contiguous text runs. Improves the usability of the results and can dramatically reduce the size of the results. 3. Combine records into buckets — Once the record list is reduced by standard aggregations, there are various ways of grouping results together. In some cases, multiple records map to one result node; in others, result nodes are grouped together. 4. Generate result nodes — To make a result node, all required strings are generated and added to the result node; then, the result node is inserted into the tree. Get the raw table of results The first step in aggregation is getting the initial table of results by collecting them from the process-database result nodes. Unless you have a good reason otherwise, use IPreflightAggregatedResultsUtils::CreateTableFromNodes for this step: Utils<IPreflightAggregatedResultsUtils> iUtils; InterfacePtr<const IPreflightResultRecordTable> iRawTable( iUtils->CreateTableFromNodes(iProcess, resultNodes)); The raw table now contains all the results added by your iVisit->CreateResultRecord() calls. Apply standard aggregations The usual next step is aggregating all results together using “standard” aggregations, using IPreflightAggregatedResultsUtils::ApplyAllStandardAggregations: InterfacePtr<const IPreflightResultRecordTable> iTable( iUtils->ApplyAllStandardAggregations(iProcess, iRawTable)); The standard aggregations utilities do the following: z All records corresponding to marking operations are aggregated into the containing object (shape, text run, table cell, etc.) that contains them. The subpart is determined automatically. Only those records with the same subpart and criteria are aggregated together. Thus, you are left with “high level” objects that can be selected, rather than artwork, which cannot. z Text runs that share the same criteria, subpart, and value are aggregated into a larger text range. Implementing Preflight Rules 485 Implementing Preflight Rules IPreflightRuleVisitor method examples z Records that share the same criteria and values, but different subparts, are aggregated together. This is done last. You do not need to call ApplyAllStandardAggregations. You do not need to make this call if your rule looks at only one object or does not look at objects that would ever be aggregated, or you simply do not want to do any standard aggregation. You also can use any of the “lesser” aggregation utilities, which do only one kind of aggregation, not all of them. Combine records into buckets After standard aggregation, the nodes are more or less ready to go into the tree; however, depending on your rule’s desired presentation, you may want to put them in buckets. The native InDesign rules put records into buckets in two ways z Single node represents multiple violation records. For example, the image-resolution rule can fail in multiple ways on the same object; in particular, when the images come from a PDF, EPS, or INDD file. Rather than creating a node for each failure, there is a single node for the PDF/EPS/INDD, and all failures are enumerated within that node’s information text. z Nodes grouped under a rule or criteria — If you just add violation nodes under parentID, typically they appear as children of a category, which usually is not desirable. (The exception is nodes that can involve only one object, like the document object; these should share both the criteria and violation in a single node.) Rather, you want a criteria node, which describes the error, with the individual violations of that error added as children of the criteria. Several methods in IPreflightAggregatedResultsUtils are useful for bucketizing. Some of these are shown in Table 124. TABLE 124 Bucketizing IPreflightAggregatedResultsUtils methods 486 Method Purpose/use CreateSubTable Use this when you have manually determined how to divide entries and want to create a new table containing just those entries (for example, for passing to your shared node-building subroutine). CreateSubTableByCriteria Use this to put all records under a common criteria node. This method creates a table with only the matching criteria, so you know all entries share that criteria. CreateTablesByCriteriaCr eateTablesByAuxString Use this to group entries under the same criteria or aux strings, and might have quite a few different criteria (or in the case of strings, you probably don’t know ahead of time how many strings to expect). This method gives you a vector of tables, each sharing entries of the same criteria or string. You can then iterate over the vector and pass each to a common formatting utility. Implementing Preflight Rules IPreflightRuleVisitor method examples Method Purpose/use CreateTablesByObject Use this to ensure that an object appears in only one node. If there are multiple criteria/subparts under that object, you just want to add more information strings. For example, this how the stroke-width rule works. You can use several of these together. For example, you could create tables by criteria, then for each of those tables, create tables by object. Remember, tables are lightweight and ref counted, so there is no record copying when creating subtables. Thus, you can use these utilities to your advantage, without worrying too much about overhead. As an example, the colorspace rule’s aggregation method looks like this: // We only want one entry per object, so divide the table into multiple tables, // one per common object. IPreflightAggregatedResultsUtils::VectorOfTables byObject; iUtils->CreateTablesByObject(iTable, byObject); int32 i, n; for(i = 0; i < byObject.size(); i++) { // Create a violation node for this object; then for each record just // add strings corresponding to that record. IPreflightResultRecordTable* iObjTable = byObject[i]; InterfacePtr<const IPreflightResultRecord> iRec( iObjTable->QueryNthRecord(0)); InterfacePtr<IPreflightResultNodeInfo> iNode( iUtils->CreateViolationNode(iRec->GetObjectID())); InterfacePtr<IPreflightResultNodeData> iData(iNode, UseDefaultIID()); iData->AddInfoString(IPreflightResultNodeData::kFieldRequired, sRequirement); // For each subpart create its own Problem line. for(n = 0; n < iObjTable->GetRecordCount(); n++) { InterfacePtr<const IPreflightResultRecord> iRec( ObjTable->QueryNthRecord(n)); Data->AddInfoString(IPreflightResultNodeData::kFieldProblem, MyMakeProblemString(iRec)); } } In the above example, some of the details are omitted. The point of the example is to show how the original, raw table, having been reduced through standard aggregation, is divided and conquered via CreateTablesByObject. Implementing Preflight Rules 487 Implementing Preflight Rules IPreflightRuleVisitor method examples Generating result nodes The final step is generating the nodes that appear in the results tree. There are three substeps: z Create the node — You can create four kinds of nodes through the existing utilities: Generic, Criteria, Violation, and Criteria/Violation. z Fill in the node’s short-form string (i.e., the one that appears in the tree view panel) — Violation nodes are self-describing through the object model, but the others require you to specify the string you want to appear. These strings also appear in the reports. z Fill in the node’s Info strings — These are label-value pairs, like “Required:” and “Text must be either blue or green.” These strings appear in the Info pane below the tree view. They also appear in the reports. To create the nodes, the IPreflightAggregatedResultsUtils methods in Table 125 are handy. TABLE 125 Methods for node creation Method Purpose CreateGenericNode Creates a generic node. Typically, this is a child of a criteria node and is used to group together like items by something other than a criteria. The native rules use this when they want to group by font name, for example. AddCriteriaNode Creates a criteria node and immediately adds it to the tree. You specify the name at the time of creation. Criteria nodes typically have no info text, which is why this does both operations. CreateViolationNode Creates a violation node; this is a node that describes a particular problem with a particular object. Thus, the name is generated automatically from the passed-in object ID, and all other behaviors are inherited automatically (page number reporting, selection, etc). CreateCriteriaAndViolationNode Creates a combination criteria and violation node. Typically, this is used for rules that check only the document or other singleton. There is not much point in having a criteria node with a violation child; that is unnecessary hierarchy. In most cases, you take the result of these methods and start adding info strings. Unless you are going to build your own implementation of IPreflightResultNodeInfo, you do this via code like the following: 488 Implementing Preflight Rules IPreflightRuleVisitor method examples InterfacePtr<IPreflightResultNodeInfo> iNode( iUtils->CreateViolationNode(iRec->GetObjectID())); InterfacePtr<IPreflightResultNodeData> iData(iNode, UseDefaultIID()); iData->AddInfoString(IPreflightResultNodeData::kFieldProblem, "The object has the wrong color."); iData->AddInfoString(IPreflightResultNodeData::kFieldFix, "Set the color to something else.") How you fill in the strings is up to you, but there are some utility methods that help with the task. Some of them are explained in Table 126. Normally, these are used along with StringUtils::ReplaceStringParameters() to handle localization properly. TABLE 126 IPreflightAggregatedResultsUtils methods that help with formatting Method Purpose/application IsPlacedContent Determines whether a given record corresponds to a placed element or a subpart of a placed element. In many cases, the recommended fix string depends on the distinction. FormatXMeasureForma tYMeasureFormatLine MeasureFormatTextSize MeasureFormatResoluti onFormatAsInteger Returns pre-translated strings ready for substitution via StringUtils::ReplaceStringParameters(). These take PMReals and return PMStrings. See below for an example. GetSubpartsDescription Returns a description of the subpart (or subparts) for a record. For example, if the subparts are kPreflightOM_NativeStroke and kPreflightOSP_NativeFill, this returns the string “Stroke, Fill”. This leverages the object model. Here is an example of how you might use the above: // Set up requirement string PreflightRuleDataHelper dh(this); PMString sRequired("Min size is ^1", PMString::kTranslateDuringCall); StringUtils::ReplaceStringParameters(&sRequired, iUtils->FormatXMeasure(dh.GetRealParam("min_size"))); iData->AddInfoString(IPreflightResultNodeData::kFieldRequired, sRequired); // Set up problem string PMString sProblem("Actual size is ^1", PMString::kTranslateDuringCall); StringUtils::ReplaceStringParameters(&sProblem, iUtils->FormatXMeasure(iRec->GetMinValue())); if (!iRec->HasCommonValue()) sProblem += PMString( " (smallest)", PMString::kTranslateDuringCall); iData->AddInfoString(IPreflightResultNodeData::kFieldProblem, sProblem); Implementing Preflight Rules 489 Implementing Preflight Rules IPreflightRuleVisitor method examples // Set up fix string if (iUtils->IsPlacedContent(iRec)) { iData->AddInfoString(IPreflightResultNodeData::kFieldFix, "Fix it in the original file."); } else { iData->AddInfoString(IPreflightResultNodeData::kFieldFix , "Use Object > Size to change the size."); } The above example is almost literally the code found in the InDesign native rules. It takes a number of lines of code to write the string generation, but this is unavoidable; the presentation depends entirely on the nature of your rule and how verbose you want the results to be. You do not need to be this fancy, but users expect more in-depth information to be presented where possible. IPreflightRuleVisitor::UpdateRuleData This method is called when a document is opened, at start-up, or when a new rule is created. It examines the rule parameters, establishes defaults, and removes any parameters that are no longer needed. This is analogous to the class constructor and converters used for stream-based data in other interface implementations. Typically, this method leverages the utilities in PreflightRuleDataHelper, which makes it easier to set defaults. The following example is from the colorspace rule: virtual void UpdateRuleData() override { PreflightRuleDataHelper dh(this); dh.SetBoolParamDefault(kParamNoRGB, kFalse); dh.SetBoolParamDefault(kParamNoCMYK, kFalse); dh.SetBoolParamDefault(kParamNoGray, kFalse); dh.SetBoolParamDefault(kParamNoLAB, kFalse); dh.SetBoolParamDefault(kParamNoSpot, kFalse);} By using SetBoolParamDefault, there will be no change if the parameter was already initialized, so this implementation works for both updating and initializing. IPreflightRuleVisitor::ValidateRuleData Preflight calls this method whenever a script sets a parameter on a rule. Since there is no range metadata in the rule data, the rule must perform any required checking. If the rule exposes no parameters with range restrictions, it can simply return kSuccess. 490 Implementing Preflight Rules More on specific objects The following example is from the bleed/trim hazard rule: virtual ErrorCode ValidateRuleData ( const IPreflightRuleData::Key& key, const ScriptData& proposedValue ) const { PreflightRuleDataHelper dh(this); if (!dh.DataExists (key.GetPlatformString ().c_str ())) return kInvalidParameterError; PMReal value = -1; if (key == kParamLiveAreaL || key == kParamLiveAreaR || key == kParamLiveAreaT || key == kParamLiveAreaB) { if (proposedValue.GetType () == ScriptData::s_double) { proposedValue.GetPMReal (&value); if (value < 0 || value > kMaxValue) return kOutOfRangeError; } else return kInvalidParameterError; } return kSuccess; } More on specific objects This section describes how to work with particular objects in the model in your Visitor. Native, UID-based objects These are the simplest to work with because their preflight object boss does not have any additional interfaces. You simply use IPreflightObject::GetModelRef to get an interface on a native (persistent) InDesign boss in the document database. There is no point in preflight providing additional interfaces on the preflight object in this case, because you can get this information from the UID and all existing InDesign model interfaces. For example, the Scaled Graphics rule always looks at graphic page items, so its Visit code looks like the following: virtual void Visit(IPreflightVisitInfo* iVisit) override { InterfacePtr<IPreflightObject> iObj(iVisit->QueryObject()); InterfacePtr<IShape> iShape(iObj->GetModelRef(), UseDefaultIID()); InterfacePtr<ITransform> iTransform(iShape, UseDefaultIID()); // etc Implementing Preflight Rules 491 Implementing Preflight Rules More on specific objects This version has error checking removed, for readability. Initially, you may want to put in several asserts in your rules, to satisfy yourself that the visitor is looking at the object it thinks it is. Artwork A rule can ask to look at marking operations. This is a powerful capability because you can look at exactly what marking is done for a particular page item or graphic element, regardless of whether you “own” the implementation of that object. Preflight renders the spread into a port, then builds a tree data structure based on what it finds. That tree consists of the marking operations, any logical artwork groups (for example, transparency groups), and groups corresponding to native InDesign elements like wax runs and page items. Unlike page items, artwork objects are not UID based, so all the information exists on the preflight object boss in interfaces that you query. Table 127 shows the artwork object types and their related interfaces. TABLE 127 Artwork preflight object types Preflight object class ID Description kPreflightOM_ ArtworkMark The most commonly inspected object type for artwork rules. The boss that the service creates for this object type has the following interfaces: kPreflightOM_ ArtworkGroup 492 z IPreflightArtworkMarkInfo — Provides information about the marking operation, such as the geometry, colorspace, opacity, and text versus path. z IPreflightArtworkContext — Relates the marking operation to any context objects of which it is a child. This is useful when you need to know whether the mark is, say, drawn as part of rendering a text run or graphic. Placeholder for future implementation. Implementing Preflight Rules More on specific objects Preflight object class ID Description kPreflightOM_ ArtworkContext “Metadata” contexts that enclose artwork. In other words, the marking operation tells you that a stroke of a specified width and color exists; the context tells you what that stroke is associated with.Preflight supports the following contexts: z Shape — The IShape-supporting page item containing the artwork. This also records the “subpart” of the shape: stroke, fill, adornments, and so on. Shape information is obtained via IPreflightArtworkShapeContext. z Text — The text with which the artwork is associated, if any. This is defined by the text model, index, and range. Text information is obtained via IPreflightArtworkTextContext. z Table — The associated table and cells, if any. This information is available from IPreflightArtworkTableContext. z OPI — If the artwork is being drawn as part of an OPI reference, this context is present. It has no data and only indicates that there is an OPI context. To determine what contexts an artwork mark is associated with, you start with the IPreflightArtworkContext interface on the mark boss; that interface allows you to search for the nearest, or any, context of a given type. You also can walk the context tree manually.You can ask to visit these context types directly, although this would be uncommon. For example, the OPI rule looks at OPI contexts, because it cares about only their existence. Regarding artwork-based rules: if a rule wants to see any of these classes (or any other class that lists these classes as parents), preflight forces artwork expansion, which is fairly expensive compared to looking at the attributes of native objects. This is one reason why the out-of-the-box default profile (Basic) does not have any artwork rules. This is not to say you should not have such rules; many native rules (like colorspace and CMY marking) are artwork rules. If you can get the information you need by inspecting attributes instead of looking at artwork, however, you probably should use attributes, which has much lower overhead. An artwork-rule visitor usually looks something like that shown below. This is actual code from the colorspace rule. virtual void Visit(IPreflightVisitInfo* iVisit) override { InterfacePtr<IPreflightObject> iObj(iVisit->QueryObject()); InterfacePtr<IPreflightArtworkContext> iContext(iObj, UseDefaultIID()); if (iContext && iContext->GetShapeContextDepth( kPreflightOSP_GraphicProxy) > 0) { Implementing Preflight Rules 493 Implementing Preflight Rules More on specific objects // Artwork is part of a graphic proxy (missing graphic); ignore } else { InterfacePtr<IPreflightArtworkMarkInfo> iMark (iObj, UseDefaultIID()); InterfacePtr<IPreflightArtworkPaintInfo> iColor (iMark->QueryColorPaintInfo()); if (!iColor) return; InterfacePtr<IPreflightArtworkCSInfo> iCS (iColor->QueryColorSpace()); // etc Note the use of IPreflightArtworkContext, which looks for an enclosing shape context with a subpart of kPreflightOSP_GraphicProxy. This identifies the marking operation as proxyrelated. Your rule may or may not want to exclude proxy artwork in this way. Once the rule determines that the artwork is not part of a proxy, it gathers the marking data, including the paint characteristics. All these secondary interfaces (e.g., IPreflightArtworkPaintInfo) are obtained via methods in IPreflightArtworkMarkInfo. In the case of the colorspace rule, it simply calls various IPreflightArtworkCSInfo methods to determine whether the marking operation violates its rule parameters. Text runs and ranges Text runs are not persistent objects, so IPreflightObject::GetModelRef will not give you a UID for one of these. Thus, a text run or range object has all its data on the preflight object boss itself. To obtain information about text objects, query for the following interfaces: z IPreflightTextRangeInfo — This interface is available on all text-range objects (kPreflightOM_TextRange, kPreflightOM_TextCharacter, kPreflightOM_WaxRun, and kPreflightOM_TextParcel). It provides the text model, thread, parcel, index, and span information for the text object. To obtain further information, you use the InDesign text model. z IPreflightWaxInfo — This interface is available only on a kPreflightOM_WaxRun object, not the other text types, since they do not necessarily correspond to a wax-run boundary. This provides the number of glyphs in the run, as well as a method that provides an IWaxRun. An example of the use of text interfaces follows (from the missing-fonts rule): virtual void Visit(IPreflightVisitInfo* iVisit) override { const PreflightObjectID& objID = iVisit->GetObjectID(); InterfacePtr<IPreflightObject> iObj(iVisit->QueryObject()); if (objID.GetClassID() == kPreflightOM_WaxRun) { InterfacePtr<IPreflightWaxInfo> iWax(iObj, UseDefaultIID()); if (!iWax) return; 494 Implementing Preflight Rules More on specific objects InterfacePtr<const IWaxRun> iRun(iWax->QueryRun()); if (!iRun) return; InterfacePtr<const IWaxRenderData> iRender(iRun, UseDefaultIID()); if (!iRender) return; if (iRender->FontFaceMissing()) { InterfacePtr<IPreflightResultRecord> iRec( iVisit->CreateResultRecord()); iRec->SetCriteria(kPreflightRC_Default); PMString fontName = iRender->GetFontName(); fontName.SetTranslatable(kFalse); iRec->SetAuxString(fontName); } } // etc Tables, rows, columns, and cells Many table elements in a document are composed of elements and may or may not have an associated UID. Thus, some of the table objects are UID based (e.g., use GetModelRef) and some are not. Those that are not have additional data on the preflight object boss. For non-UID based elements, the IPreflightTableCellInfo interface on the preflight object boss provides the necessary data, from which you can navigate to the InDesign model. The objects that support this interface are kPreflightOM_TableCell, kPreflightOM_TableArea, kPreflightOM_TableFrameCell, and kPreflightOM_TableFrameArea. The following is an abbreviated example from the overprint rule, which looks for any overprint attributes that are set. In this case, the rule is interested in page items, text, and tables, all of which have overprint attributes. virtual void Visit(IPreflightVisitInfo* iVisit) override { PreflightObjectID objID = iVisit->GetObjectID(); InterfacePtr<IPreflightObject> iObj(iVisit->QueryObject()); if (objID.GetClassID() == kPreflightOM_PageItem) { InterfacePtr<IGraphicStyleDescriptor> iStyle(iObj->GetModelRef(), UseDefaultIID()); // Check graphic attributes.. } else if (objID.GetClassID() == kPreflightOM_WaxRun) { InterfacePtr<IPreflightTextRangeInfo> iRange(iObj, UseDefaultIID()); if (!iRange) return; // Check text attributes via the text model... } Implementing Preflight Rules 495 Implementing Preflight Rules More on specific objects else if (objID.GetClassID() == kPreflightOM_TableFrame) { InterfacePtr<ITableFrame> iFrame(iObj->GetModelRef(), UseDefaultIID()); if (!iFrame) return; // Check the table attributes... } else if (objID.GetClassID() == kPreflightOM_TableFrameCell) { InterfacePtr<IPreflightTableCellInfo> iCellInfo(iObj, UseDefaultIID()); if (!iCellInfo) return; // Check the cell attributes.. } } Note how the rule must use a different strategy for each object type. For page items and tables there is a UID to work with, so it queries the model directly. For text and cells, which are composed entities, the rule uses the interfaces hosted on the preflight object directly: IPreflightTextRangeInfo for text and IPreflightTableCellInfo for table cells. For example, the first thing it does when looking for cell attributes is to look up the table attribute’s accessor interface from the table model, using IPreflightTableCellInfo::GetTableModelRef: InterfacePtr<ITableAttrAccessor> iTableAttrs( iCellInfo->GetTableModelRef(), UseDefaultIID()); if (!iTableAttrs) return; 496 XML Fundamentals Introduction XML Fundamentals This chapter describes features of the InDesign XML subsystem relevant to plug-in developers, and the architecture that supports them. It explains how client code can use these features and take advantage of the XML-related extension patterns in the InDesign API. For use cases, see the “XML” chapter of Adobe InDesign CS4 Solutions. Introduction XML-based workflow There are several benefits of using an XML workflow in publishing: z Separation of concerns; for example, maintaining content and presentation information independently. z Working with standards that are open, relatively stable, and defined by experts in a domain. This avoids being locked into proprietary, unpublished file formats and helps reduce implementation effort. For example, having standards available like NITF (http://www.nitf.org) and NewsML (http://www.newsml.org) prevents you from having to reinvent a language to store articles, transmit news feeds, and support a newspaper workflow. z Relatively easy processing, because you have a textual representation of XML documents. z Relatively easy re-purposing of content for other media, like HTML and Mobile SVG, in addition to print publishing and PDF delivery. The main advantage is that the content can be single-sourced but published to multiple media with relatively little effort. z Relatively easy manipulation of XML documents, thanks to the availability of many XMLaware tools, software developer toolkits, and standardized APIs. z Existence of many databases that can produce and consume XML data, some natively. Disadvantages to an XML workflow can include the following: z Journalists and graphic designers are unlikely to want to learn about XML. A system designed around XML may need to shield end users from having to create mark-up manually. For example, templates can be pre-tagged. z Some XML technologies are not straightforward to use and may require some effort to understand (for example, XSLT/XPath), even for capable software developers. XML Fundamentals 497 XML Fundamentals Terminology Using XML with InDesign Using XML-based data and XML templates in InDesign has some benefits to a programmer, which include the following: z There are mature XML toolkits and technologies to manipulate XML data (see http://xml.coverpages.org/software.html), which make it relatively straightforward to manipulate XML data before import or after export. For example, using XSLT to manipulate XML data is particularly convenient in the context of the InDesign import architecture. You can develop and debug your XSL stylesheets independently of InDesign, using existing XSLT-aware tools, but deploy them as part of a workflow involving InDesign if you use its features like the XML transformer. See “XML transformer” on page 554. z Importing graphics into tagged placeholders is a convenient way to import and place graphics without writing much (if any) code. See “Tagged graphic placeholder” on page 534. z The XML API of InDesign is well documented. The command facades and suite interfaces in the XML API make it relatively straightforward to write client code. See “Key client API” on page 552. Terminology See the “Glossary” for definitions of terms. Table 128 lists terms used in this chapter and sections that relate to them. TABLE 128 Terminology 498 Term See ... Acquirer; acquirer filter “Extension patterns” on page 553 Backing store “Backing store” on page 509 Comment, XML “Processing instructions and comments” on page 547 Content handler “Extension patterns” on page 553 Content item “Content items” on page 506 Document element “Document element and root element” on page 508 Document Type Declaration (DTD) “DTD” on page 545 Entity “SAX-entity resolver” on page 557 Logical structure “Native document model and logical structure” on page 505 and “Elements and content” on page 534 Placed element; placed content “Unplaced content versus placed content” on page 518 XML Fundamentals XML features at a glance Term See ... Processing instruction (PI) “Processing instructions and comments” on page 547 Repeating element “Importing repeating elements” on page 519 Root element “Document element and root element” on page 508 SBOS (small boss object store) “Persistence and the backing store” on page 510 Tag “Tags” on page 529 Unplaced element; unplaced content “Unplaced content versus placed content” on page 518 XML element “Elements and content” on page 534 XML features at a glance XML extension patterns Several XML extension patterns depend on the re-factored XML import architecture. You can implement these extension patterns to customize how XML data is imported and exported and other XML-related features. See “Extension patterns” on page 553. Tagging in tables and inline graphics InDesign supports tagging of tables and table cells. See “Tagged tables” on page 543. Inline graphics can be tagged, and placeholders for inline graphics can be created in XML templates. See “Tagged inline graphics” on page 542. Throw away unmatched existing (right) It may be desirable to filter out elements in your XML template that are not matched by elements in the incoming XML data. When enabled, this features discards unmatched existing elements in an XML template. See “Throwing away unmatched existing elements on import (delete unmatched right)” on page 520. The feature is implemented by an import-matchmaker service, an extension pattern described in “XMl-import matchmaker” on page 555. XML Fundamentals 499 XML Fundamentals XML features at a glance Throw away unmatched incoming (left) It may be desirable to filter out incoming XML elements that have no corresponding match in your XML template. When enabled, this feature discards inbound elements in the XML-based data being imported that have no match in the XML template into which the data is being imported. In API terms, the feature is called “throw away unmatched left.” See “Throwing away unmatched incoming elements on XML import” on page 522. The feature is implemented by an import-matchmaker service, described in “XMl-import matchmaker” on page 555. Importing repeating elements This feature allows text styling from elements in an XML template to be preserved (within one story) when repeated elements are imported. It is described in “Importing repeating elements” on page 519. Importing CALS table This feature allows CALS table to be imported as InDesign table. It is described in “Importing a CALS table as an InDesign table” on page 524. Support for DOM core level 2 This specification is implemented by the features related to matching and transforming on import. Import matchmakers and XML transformers that operate on the DOM (Document Object Model) are described in “Extension patterns” on page 553. For the DOM Level 2 Core specification, see http://www.w3c.org/TR/2000/REC-DOM-Level-2-Core-20001113. Support table- and cell-styles import This feature allows table and cell styles to be applied to InDesign table when is imported. It is described in “Support table and cell styles when importing an InDesign table” on page 524. Support XML-rules processing The scripting-based XML-rules feature allows an XML DOM to be altered after an XML file is imported. XML rules also can be triggered by application events, such as open, place, and close. The feature is described in the “XML Rules” chapter of Adobe InDesign CS4 Scripting Guide. Snippets The snippet architecture is described in the “Snippet Fundamentals” chapter. The snippet architecture depends on the XML subsystem, as well as on INX (InDesign Interchange) or IDML (InDesign Markup Language) import and export. Snippets are XML-based representations of parts of a document in INX or IDML file format. 500 XML Fundamentals The user interface for XML The user interface for XML Structure view Figure 215 shows the structure view, a representation of the logical structure of a document that lets you view and interact with its logical structure. You can make selections in this view and create new elements as children of the selection, delete elements, create or delete attributes, and so on. Figure 215 shows the structure view with text snippets visible, which provides context to see what content items in the document are associated with the elements in the logical structure. FIGURE 215 Structure view Depending on your workflow, it may be desirable to control the visibility and other properties of the Structure pane. These properties are controlled by preferences. See “XML-related preferences” on page 549. When you tag a graphic frame as a placeholder, the structure view draws a cross through the icon representing the element to indicate its placeholder status. There are also other icons that represent whether an element is associated with text content or image-based content. Tags in layout view and story view Figure 216 shows content that has been tagged, rendered in the layout view of the application. In layout view, tags are shown as brackets with a width of zero; that is, they are intended to have no effect on text composition. Start tags are indicated by brackets pointing right ([), and end tags by brackets pointing left (]). The tag name associated with the tag markers is encoded by color, corresponding to the color displayed in the Tags panel. Multiple tags can exist at the same position in layout view. XML Fundamentals 501 XML Fundamentals The user interface for XML FIGURE 216 Tags in layout view Story view makes it somewhat easier to understand the logical structure of a story and edit its structured content. Figure 217 shows structured content rendered in story view. In this view, the names of tags are shown explicitly. FIGURE 217 Tags in story view Tags panel Figure 218 shows part of the Tags panel, which has a list of tags that can be applied to document content. Each tag has a name and associated color. In this example, some tags were created when a DTD was imported, shown with icons at the right-hand end of the list elements. FIGURE 218 502 Tags panel XML Fundamentals The user interface for XML To open the Tags panel, choose Window > Tags. By default, the list of tags shown is sorted alphabetically by tag name; the list has no inherent logical structure. The complete set of tags in an imported DTD or imported tag list is shown, regardless of what is selected in the structure view. To populate the tag list, end users can load a set of tags with the Load Tags menu command in the Tags-panel menu. You can create a new tag through the Tags panel; this adds an entry to the tag list. Creating a new tag means it is available to mark up content or tag placeholder graphic frames for content. You can delete a tag through the Tags panel. You can export the tag with the Save Tags menu command in the Tags-panel menu. Mapping between tags and styles You can choose to apply a mapping between element names and styles (character and paragraph styles). Once the mapping is applied to a document, any marked-up text is styled as specified by the style on the right-hand side of this mapping. See Figure 219. FIGURE 219 User interface for mapping tags to styles An important use case for mapping tags to styles is preparing a document for XML import. Assuming XML-based content does not carry style information, the tag-to-style map is a simple mechanism to apply styling to inbound XML-based content; more complex mechanisms include styling based on XSLT or a proprietary mechanism like an Adobe FrameMaker Element Definition Document (EDD). The FrameMaker EDD effectively is a style sheet containing rules specifying how to map tags to styles, but in a context-dependent way. You can apply structure to an unstructured InDesign document by choosing to map styles to tags. The effect of this is to mark up the text ranges that have the styles on the left-hand side of the style-to-tag mapping. See Figure 220. XML Fundamentals 503 XML Fundamentals The user interface for XML FIGURE 220 User interface for mapping styles to tags Validation window The XML-validation-errors pane appears below the Structure pane; see Figure 221. The XMLvalidation-errors pane contains hyperlinks. If the end user clicks on the hyperlinks, InDesign tries to fix the validation errors. This may not always have the desired effect; for example, it may delete content that was tagged incorrectly. FIGURE 221 XML-validation-errors pane Other Other components of the user interface for XML—like context-sensitive menus for tagging the selection—are beyond the scope of this chapter. 504 XML Fundamentals XML model XML model Native document model and logical structure The InDesign native document model specifies how end-user documents are represented by InDesign. The InDesign native document model consists of both the description of the document in terms of boss classes and the scripting DOM. End users directly manipulate spreads, pages, and the items they contain; these abstractions are represented by boss classes in the native document model or objects in the scripting DOM. For example, a spread is represented by kSpreadBoss in the low-level model or boss DOM. Spread contents are organized into a hierarchy (IHierarchy). In the scripting DOM, a spread is represented by a Spread object, with properties like Pages or PageItems to represent the object hierarchy at a higher level of abstraction. The logical structure of an InDesign document is specified by the user; for example, by tagging content items in the layout or importing their XML data. An XML template, consisting of tagged placeholders for text and graphics, provides the user with a way to define how userdomain data is mapped into the native model. The logical structure of an InDesign document is organized into a hierarchy of XML elements (see IIDXMLElement) representing logical relationships between content. The IIDXMLElement interface plays the same role in the logical structure that IHierarchy plays in the spread hierarchy. The key operation that modifies logical structure is tagging document objects, like graphic frames, stories, and text ranges. Tagging establishes associations between objects in the native document model and the logical structure. See “Elements and content” on page 534. Importing XML-based data into an InDesign document creates new elements in the logical structure (see “Importing XML” on page 511). If there are tagged placeholders, content can be flowed into these placeholders. The logical structure of an InDesign document also can be exported as an XML file (see “Exporting XML” on page 524). You also can create new elements by mapping styles to tags (see “Tags” on page 529). Elements and attributes Elements represent user-defined logical relationships between content items in a document. Elements are created by InDesign when XML data is imported or content is tagged. The implementation of elements in InDesign is closely related to the XML specification (http://www.w3.org/TR/REC-xml), which defines an element as follows: “Each XML document contains one or more elements, the boundaries of which are either delimited by start-tags and end-tags, or, for empty elements, by an empty-element tag. Each element has a type, identified by name, sometimes called its “generic identifier” (GI), and may have a set of attribute specifications. Each attribute specification has a name and a value.” You can create a new element in the logical structure with the New Element menu command on the Structure-pane menu. The behavior of this feature depends on whether the element in the structure view already is placed and, if placed, what is the associated content item. You can XML Fundamentals 505 XML Fundamentals XML model choose a tag for the element or create a new one. The tag stores the element’s name and color in the user interface. Figure 222 shows what happens when the root element is selected in the structure view and the user chooses the New Element menu command. The application adds a child element to the logical structure’s root element. By default, the child element is added at the end of the collection of child elements of the root element. In this example, the root element <book> is selected and a new element <article> is added. The new element is inserted into the logical structure as the last child of the root element and is shown as unplaced content, since the top-level element was not placed; only its child elements are placed content. FIGURE 222 Inserting a new element You can add an element to the logical structure in the structure view, in which case the element is not directly associated with document content. You can indirectly add one or more elements in another view, like layout view, by tagging (e.g., tagging a text range or graphic placeholder frame). Attributes are properties of elements. Attributes can be added by end users through the structure view, when a node is selected that supports added attributes. Some elements, like comments, processing instructions, and the DTD element, do not support the addition of attributes. Elements are modeled by boss classes that have the IIDXMLElement interface. Tags are modelled by the kXMLTagBoss boss class. See “Tags” on page 529. Attributes are modeled as properties of elements (IIDXMLElement). There are facades that make it relatively easy to change the properties of elements, tags, and attributes (IXMLElementCommands, IXMLTagCommands, and IXMLAttributeCommands). Content items Elements (IIDXMLElement) are created when content items are tagged. Elements also may be created on import of XML data. New content items can be created when XML content is flowed into an XML template. The main point is that elements are defined in the user domain and represent logical relationships between content items—or between elements, in the case of structural elements. Content items are objects in the layout or text domain that can be tagged to create an association with an element in the logical structure of an InDesign document. Many content items can be tagged: 506 XML Fundamentals XML model z Placeholders for graphics (kPlaceHolderItemBoss) z Placeholders for inline graphics (kILPlaceHolderPageItemBoss) z Images (kImageItem, any other descendants of kImageBaseItem) z Stories (kTextStoryBoss) z Text ranges z Tables (kTableModelBoss) and cells within them z Text within table cells There is no easy way to identify a content item. Many but not all the objects that can be tagged have the IXMLReferenceData interface. If you inspect the API reference documentation for IXMLReferenceData and see the boss classes in the native document model that aggregate this interface, you get some indication of the variety of document objects that can be tagged. References to elements and content items All elements in the logical structure of an InDesign document expose the IIDXMLElement interface; therefore, one type of reference to an element is an interface pointer of type IIDXMLElement. A more convenient type for programmers to work with is XMLReference, an instance of which can be obtained from IIDXMLElement::GetXMLReference. This XMLReference is just another way to refer to the same element. Conversely, given an XMLReference, you can obtain an IIDXMLElement interface pointer by using XMLReference::Instantiate. XMLReference is the XML subsystem’s equivalent of UIDRef; note that UIDRef applies only to UID-based objects, and elements in the logical structure are not UID-based. XMLContentReference refers to a chunk of content rather than an element. Do not mistake the XMLContentReference type for XMLReference: XMLContentReference is a reference to a content item, which might be a UID-based like a graphic frame or a non-UID-based object like a table cell. An instance of XMLContentReference can be obtained from IIDXMLElement::GetContentReference. This generalizes and replaces IIDXMLElement::GetContentItem, which is deprecated. An instance of XMLContentReference can tell you the type of object with which it is associated, through XMLContentReference::GetContentType. For example, kContentType_Normal is used for elements associated with a UID-based object in the layout; this could be something like a tagged graphic placeholder. For more information on methods and use of these key types, see the API reference documentation for XMLReference and XMLContentReference. The main difference between XMLReference and XMLContentReference is that XMLReference refers to an element (IIDXMLElement), whereas XMLContentReference refers to a content item. XML Fundamentals 507 XML Fundamentals XML model Document element and root element The IXMLReferenceData interface on kDocBoss stores a reference to the document element (instance of kXMLDocumentBoss). There also is an interface on the document (kDocBoss), with a different PMIID referring to the DTD element (kXMLDTDBoss), if one is associated with the document. The document element associates with the root element both through IXMLReferenceData (as shown in Figure 223) and through IIDXMLElement::GetNthChild, because the document element is the parent of the root element. The class diagram in Figure 223 shows associations involving the document element (kXMLDocumentBoss) and other classes. FIGURE 223 Document element, root element, and DTD 1 «boss» kDocBoss IXMLReferenceData::GetReference IXMLUtils::QueryRootElement 1 IXMLUtils::QueryDocElement is another way to navigate this association. 1 1 IXMLReferenceData::GetReference «boss» kXMLDocumentBoss 1 «boss» kTextXMLElementBoss 1 1 IXMLReferenceData::GetReference 0..1 Interface with PMIID of IID_IXMLDTDXMLREFERENCEDATA on kXMLDocumentBoss refers to the DTD object, if one exists. «boss» kXMLDTDBoss The document element is responsible for managing document-level information (like the DTD) and comments and processing instructions that are peers of the root element. The root element (kTextXMLElementBoss) appears as the root of the element hierarchy in the structure view, although the root element is a child of the document element, which is not shown in the structure view. By default, the root element for a new InDesign document has the tag Root; you can change this to whatever the content model for your XML vocabulary requires. 508 XML Fundamentals XML model The document element and root element—along with the DTD element and any top-level comments (kXMLCommentBoss) and processing instructions (kXMLPIBoss)—are held in the backing store. Backing store Each InDesign document contains one backing store, which stores XML elements that are unplaced and elements that are siblings of the root element, like the document element, root element, DTD element, comments, and processing instructions. The backing store is a story (kTextStoryBoss) that is not accessible to the user and is present in every InDesign document. The architecture of the backing store is described in “Persistence and the backing store” on page 510. The object diagram in Figure 224 shows the relationship between the document, backing store, and elements stored in the backing store. FIGURE 224 Backing store There is exactly one backing store for a document, an instance of a story (kTextStoryBoss) that is not user-accessible. It stores XML elements that are not on the page and other elements, such as the document element. «boss» document : kDocBoss Backing store (opaque) «boss» doc-elem : kXMLDocumentBoss XML Fundamentals «boss» article : kTextXMLElementBoss «boss» title : kTextXMLElementBoss 509 XML Fundamentals XML model The backing store is opaque to client code. Use facade methods like IXMLUtils::QueryDocElement and IXMLUtils::QueryRootElement to acquire objects like the document element (kXMLDocumentBoss) or the root element (shown as the article object in Figure 224). To acquire a reference to the backing store when you need it (e.g., for notification), use IXMLUtils::GetBackingStore. For more information, see “Backing store and notification of changes in logical structure” on page 558. Persistence and the backing store The main persistence mechanism for the native document model is UID-based; that is, each instance of the classes shown in the model, like kSpreadBoss, has a record number or UID (unique identifier) associated with it in the document’s database. The UID is unique only within the context of a particular database, not globally. UID-based objects also can store persistent boss objects without a UID; for example, this model is used for attributes and widely within the table and XML subsystems. This as an example of container-managed persistence, to distinguish it from the conventional, UID-based persistence mechanism. The implementation of container-managed persistence in InDesign is very efficient compared to UID-based persistence, which played a large part in the decision to use it for both tables and XML. For more information, see the “Persistent Data and Data Conversion” chapter. This object diagram in Figure 225 is an elaborated version of Figure 224. The BaseUID shown for each object is the UID of the kTextStoryBoss implementing the backing store. The LSID (logical structure ID) starts at 1 for the document element (kXMLDocumentBoss). See the API reference documentation for XMLReference. The root element, with LSID of 2 in this diagram, is an instance of kTextXMLElementBoss; it has a reference to a tag (TagUID=126, name= “Root”) but not to a content item. The image element has a reference to a tag (TagUID=159, name= “image”) and to a content item (UID=161, an instance of kPlaceHolderItemBoss). 510 XML Fundamentals Importing XML FIGURE 225 Backing store, with more detail «boss» document : kDocBoss Backing store (opaque) «boss» doc-elem : kXMLDocumentBoss «boss» Root : kTextXMLElementBoss «boss» image : kTextXMLElementBoss BaseUID = 111 LSID = 1 BaseUID = 111 LSID = 2 ContentItemUID = 0 TagUID = 126 BaseUID = 111 LSID = 3 ContentItemUID = 161 TagUID = 159 The backing store is an instance of a small-boss object store (SBOS), a storage container for small boss objects. The container has a UID, but the objects it stores do not have UIDs. The objects managed by the store have logical IDs (LSIDs) as keys. See the API reference documentation for XMLReference::GetLogicalID and related methods. Importing XML The application supports import of XML data encoded as any of the following: z UTF-8 (see http://www.ietf.org/rfc/rfc2279.txt) z UTF-16 (see http://www.ietf.org/rfc/rfc2781.txt) z Shift-JIS, a two-byte format for Japanese (see http://www.w3.org/TR/2000/NOTE-japanesexml-20000414) XML Fundamentals 511 XML Fundamentals Importing XML There are two main workflows for importing XML data: z Importing XML data into the backing store (see “Backing store” on page 509), then manually placing it onto the layout to set up the associations between elements in the logical structure and document object. z Creating an InDesign document as an XML template that contains placeholders, which are tagged with names of the elements in the XML data to import. When the XML data is imported, the contents of the XML file are flowed into the placeholders. The order in which the elements appear in the logical structure determines how the content is flowed into the tagged placeholders. Import architecture The import process is controlled by the XML importer (kXMLImporterBoss), which is the main delegate for the low-level command that performs the import (kImportXMLFileCmdBoss). Unlike other forms of import—like EPS (import provider kEPSPlaceProviderBoss) and PDF (import provider kPDFPlaceProviderBoss) import—importing XML data does not use the standard import provider (IImportProvider) architecture. The importer controls the import process by dispatching messages to extension patterns responsible for different parts of the import sequence, as shown in Figure 226. The sequence diagram shows some of the messages sent during XML import. The importer object shown consists of the low-level import XML command (kImportXMLFileCmdBoss) and its delegate (kXMLImporterBoss). The main points to note are the order in which the different extension patterns are sent messages and, for the transformer (IXMLTransformer), how the stream transform precedes the DOM transform message. 512 XML Fundamentals Importing XML FIGURE 226 Importer XML-import sequence Acquirer Transformer Matchmaker Serializer handler Post-import iterator IXMLAcquirerFilter::CreateStreamAndResolver IXMLTransformer::TransformStream IXMLTransformer::TransformDOM IXMLImportMatchMaker::MatchDocument ISAXDOMSerializerHandler::StartDocument IXMLPostImportIteration::BeforeIteration A low-level command (kImportXMLFileCmdBoss) is processed to import an XML file. Much of the work is done by this command’s delegate, an instance of the kXMLImporterBoss boss class, in its implementation of IXMLImporter::DoImport. The following operations are performed while importing an XML file: 1. The import parameters are specified through an instance of kImportXMLDataBoss. In particular, see IImportXMLData. This specifies either an IDFile (based on a path, which may be a file path or an arbitrary URL-like string). 2. An acquirer service (IXMLAcquirerFilter) is located, which knows how to turn the import specification (in IImportXMLData) into an XML stream, perhaps with a SAX entity resolver. See “XML acquirer” on page 553 and “SAX-entity resolver” on page 557. 3. The SAX parser service (kXMLParserServiceBoss, ISAXServices) parses the inbound XML from the stream. 4. XML transformer services (kXMLImporterTransformerService) are called to transform the stream. See “XML transformer” on page 554. 5. At this point, the stream has been turned into an XML DOM. XML transformer services are called to transform the DOM. See “XML transformer” on page 554. 6. The XML-import match driver calls XML-import matchmaker services (kXMLImportMatchMakerSignalService) to participate in matching the input XML data against the XML XML Fundamentals 513 XML Fundamentals Importing XML template (the logical structure of the document into which content is being imported). See “XMl-import matchmaker” on page 555. 7. Matches are registered by the XML match recorder (IXMLImportMatchRecorder) of the importer (kXMLImporterBoss). 8. SAX DOM serializer handlers (ISAXDOMSerializerHandler) are called to create content based on the DOM. See “SAX DOM serializer handler” on page 557. The parsing of the final input XML data is controlled by a top-level SAX DOM serializer handler (kSAXDocumentHandlerBoss). Dependent SAX DOM serializer handlers turn parts of the DOM into InDesign content. 9. Post-import responders are called to iterate the DOM and take appropriate action. See IXMLPostImportIteration and “Post-import responder” on page 555. When XML data is imported, the XML subsystem creates elements (IIDXMLElement) in the logical structure. See “Elements and content” on page 534. Import of XML data results in content items (IXMLReferenceData) being populated with the imported content, if the content items are tagged before import. After import, unplaced elements are held in the document’s backing store. See “Backing store” on page 509. The UML diagrams in Figure 227 show some interfaces involved in storing options for import and export of XML data at the session level (kWorkspaceBoss) or document level (kDocWorkspaceBoss). There are other interfaces specific to individual components in the XML import architecture (e.g., IXMLImportPreferences, which can be found on service boss classes), which are not shown here. FIGURE 227 Some preferences related to import and export IXMLExportSessionOptions «boss» kWorkspaceBoss IXMLImportOptions IXMLExportOptions «boss» kDocBoss IDocument «boss» kDocWorkspaceBoss 514 IXMLImportOptions IXMLExportOptions XML Fundamentals Importing XML Importing a minimal XML file A new, empty document has a logical structure consisting of one Root element. To construct a slightly less trivial example, you can create a new document and import a minimal XML file into the backing store. The content is as shown in Example 35. EXAMPLE 35 Minimal XML data to be imported <article><title>Hello World</title> </article> The scenario to perform the import is as follows: 1. Save the XML data above to a text file, hello-world.xml. 2. Create a new InDesign document. 3. Show the structure view. Rename the Root tag to be “article.” 4. Create a new tag named “title.” 5. Import the XML data from the hello-world.xml file. The structure view should look like Figure 228. The objects created and instances of associations between them are shown in Figure 228. The UML object diagram shows the objects involved in representing the logical structure when minimal XML content is imported into the backing store of a new InDesign document. The logical structure of the InDesign document represents the tree structure of the original XML document, which has one title element as a child of the root-article element. Instances of the associations with the objects that represent tags are shown (kXMLTagBoss). XML Fundamentals 515 XML Fundamentals Importing XML FIGURE 228 Objects representing elements in logical structure and tags «boss» doc-elem : kXMLDocumentBoss IIDXMLElement «boss» article : kTextXMLElementBoss IXMLTag «boss» article-tag : kXMLTagBoss IIDXMLElement «boss» title : kTextXMLElementBoss IXMLTag «boss» title-tag : kXMLTagBoss Given a reference to the document (IDocument) or a document database (IDataBase), you can acquire a reference to the document element or root element in the logical structure, using the IXMLUtils facade. The document element has no tag, but the root element always has a tag; in this example, it is named “article.” The IIDXMLElement::GetTagString method discovers the tag name of an element. The root element is one starting point for traversing the logical structure. For the minimal example, you can start from the root element and look at its children. 516 XML Fundamentals Importing XML XML elements have the signature interface IIDXMLElement. Given an IIDXMLElement interface, you can obtain an XMLReference, another way to refer to an XML element. See IIDXMLElement::GetXMLReference. Conversely, given an XMLReference, you can get an IIDXMLElement interface through XMLReference::Instantiate. XML elements are described in more detail in “Elements and content” on page 534. The UML object diagram in Figure 229 shows instances of associations between a document (kDocBoss), document workspace (kDocWorkspaceBoss), and objects representing tags (kXMLTagBoss) and their colors within the Tags panel (kUIColorDataBoss). XML Fundamentals 517 XML Fundamentals Importing XML FIGURE 229 Objects representing tags and colors «boss» document : kDocBoss IDocument «boss» doc-workspace : kDocWorkspaceBoss IXMLTagList IXMLTagList «boss» article-tag : kXMLTagBoss «boss» title-tag : kXMLTagBoss IPersistUIDData IPersistUIDData «boss» red-col : kUIColorDataBoss «boss» green-col : kUIColorDataBoss Interface IPersistUIDData that stores UID of color object has the identifer (PMIID) of IID_ICOLORPERSISTUIDDATA on kXMLTagBoss. Unplaced content versus placed content When XML content is imported with default options and there are no tagged placeholders for the incoming content, the content is held in the backing store. See “Backing store” on page 509. 518 XML Fundamentals Importing XML XML template An XML template is an InDesign document with tagged placeholders. These can be any of the following: z Stories z Text ranges z Graphic frames z Tables and table cells In addition, for the template to be useful, it is likely to already have some styles established and a mapping from tags to styles. See “Tag-to-style mapping” on page 531. Matching against an XML template When XML data is imported into an XML template that matches elements in the imported XML data, some or all of the content becomes placed. Determining what constitutes a match is not a straightforward process. Architecture Matching against an XML template is performed by XML-import matchmaker services (IXMLImportMatchMaker), which implement the matching logic. For a description of this extension pattern, see “XMl-import matchmaker” on page 555. There are several existing import matchmaker services that support the import features; for example, for importing structured tables or repeating elements. For a more complete listing, see the API reference documentation for IXMLImportMatchMaker and the boss classes that aggregate this interface. If you implement your own import matchmaker, you can customize how the matching against the template is done. For example, you might want to add new pages to the document when you encounter certain repeating elements in the incoming XML data or perform some other operation not provided by the application. For details, see “XMl-import matchmaker” on page 555. Importing repeating elements Suppose you have XML-based content that consists of many very similar elements, like classified advertisements for used automobiles. You want an XML template that can handle repeating elements in the incoming XML data, rather than having to specify up front how many advertisements could be flowed into the template. In designing an XML template, it often is desirable to design only one instance of a repeating substructure and, during import, have all incoming instances of the substructure pick up the design of that instance. Often, the number of instances in the incoming XML data is either unknown or variable, so having the ability to handle repeating elements adds flexibility. During XML import, InDesign examines the incoming XML data's structure, compares it to the existing structure in the XML template, and makes duplicates of the existing template element as necessary when it detects the incoming elements are repetitions of the existing template element. XML Fundamentals 519 XML Fundamentals Importing XML Suppose you are going to import this hypothetical XML data related to classified advertisements for motor vehicles. The fields in the XML template tagged with the names of the different elements may be styled differently. The number of items in the incoming XML data is unknown. You may set up a template structure like that in Example 36. EXAMPLE 36 Sample XML template <classifieds> <advert> <vehicle> <year></year> <make></make> <model></model> <mileage></mileage> <price></price> ... </vehicle> <contact> <name></name> <phone></phone> </contact> </advert> </classifieds> In this case, the “advert” element is the repeating element. You would set up styling for the fields in each advert element. During XML import, InDesign duplicates the repeatable advert element as many times as there are elements in the incoming XML. When the data is imported into the XML template, the fields under advert retain the original styling throughout the duplication process, so the final outcome is that there are as many advert elements as there advert elements in the incoming XML. Architecture The feature is implemented by an import matchmaker service (IXMLImportMatchMaker) whose ClassID is kXMLRepeatTextElementsMatchMakerServiceBoss, which is responsible for duplicating elements in the XML template to accommodate the incoming XML elements. The feature is turned on or off by an XML import preference (IXMLImportPreferences); see “Service-level XML preferences” on page 551. Throwing away unmatched existing elements on import (delete unmatched right) You can choose to throw away (delete) unmatched existing elements on import, to filter out XML template elements that do not have a match in the incoming XML data. This might occur if, for example, your XML template contains placeholders for all possible elements in the incoming XML, including optional elements, and the incoming XML does not contain some of the optional elements. If an element (like a byline element) in your XML template is not matched in the actual content, you would not want to leave this unnecessary element in the logical structure of the document. This feature removes any unmatched optional elements (and 520 XML Fundamentals Importing XML their content) in the document after XML import. The user sets this import option in the XML Import Options dialog box. Suppose you have an XML template with the logical structure and existing mark-up shown in Figure 230. If the feature to throw away unmatched existing elements is enabled before importing XML, and the inbound XML does not have elements that match a copyright element in the template, the copyright element in the template is deleted on import. FIGURE 230 XML template For example, suppose the incoming XML contains only the elements shown in Example 37, rather than the full set of elements in the XML template document in Figure 230. EXAMPLE 37 Sample XML to import <article><headline>Another Disastrous Night for Scotland</headline> <byline>Chick O'Young</byline> <dateline>22 July 2004</dateline> <body><para>Scotland's World Cup qualification hopes were dampened by the news that no-one in the current squad is fit to play for Scotland.</para></body> </article> The net result of importing the sample XML with the option to throw away unmatched existing elements is that only the elements in the incoming XML data explicitly matched in the template are retained, and the template elements and associated content are deleted from the document on import. The result for this sample XML is shown in Figure 231. XML Fundamentals 521 XML Fundamentals Importing XML FIGURE 231 After throwing away unmatched existing elements on import Architecture This feature is implemented by a matchmaking service (kXMLThrowAwayUnmatchedRightMatchMakerServiceBoss); see “XMl-import matchmaker” on page 555. The feature is turned on or off by a service-specific import preference (IXMLImportPreferences); see “Service-level XML preferences” on page 551. For more information on controlling the feature, see the “XML” chapter of Adobe InDesign CS4 Solutions. Throwing away unmatched incoming elements on XML import You can choose to throw away (delete) unmatched incoming elements, to filter out elements in the incoming XML data that do not have a match in the XML template into which they are being imported. You can use this feature when you know there are optional elements in the incoming XML that you do not want to display, and you do not want to use XSLT to explicitly filter them out. Architecture This feature is implemented by a matchmaking service (kXMLThrowAwayUnmatchedRightMatchMakerServiceBoss); see “XMl-import matchmaker” on page 555. This feature is turned on or off by a service-specific import preference (IXMLImportPreferences); see “Service-level XML preferences” on page 551. For more information on controlling the feature, see the “XML” chapter of Adobe InDesign CS4 Solutions. Attribute-style mapping Suppose you want to import XML that has (or is transformed to have) attributes that specify the character or paragraph style to apply to text content in the inbound XML. You can use the attribute-style mapping feature, which looks for attributes pstyle and cstyle in the inbound XML, then tries to match these to paragraph and character styles in the document. Architecture This feature is implemented by a post-import responder (kXMLImporterPostImportMappingBoss); see “Post-import responder” on page 555. This responder also implements tag-to-style 522 XML Fundamentals Importing XML mapping on import; see “Tag-to-style mapping” on page 531. For information on how this feature is turned on or off, see “Service-level XML preferences” on page 551. Creating links on XML import When XML is imported into an XML template, the default behavior is not to create a link to the imported XML file; however, it is possible to turn on a feature that supports creating a link to the imported XML file. XML linking is a feature that enables InDesign to keep track of imported XML files. Each imported XML file has a corresponding link, which is shown in the Links panel along with status. Operations that can be performed on XML links include the following: z Create — When an XML file is imported, a link (kXMLImportLinkBoss) is created and associated with the root element of the imported content. Only one link can be associated with one element. Importing into an element that already has a link replaces the old link with the new one. z Delete — Deleting an element deletes its associated link, if it has one. z Copy, paste, duplicate — When an XML element associated with a link is copied, pasted, or duplicated, a copy of the link is created and associated with the new element. z Place — Placing an element into the layout or unplacing it does not affect its XML link. Both placed and unplaced elements can be associated with XML links. z Check status — An XML link's status (e.g., up-to-date, modified, or missing) is shown as an icon in the Links panel. Architecture This feature is controlled by an XML-related preference. For details on how this feature is turned on or off, see “Service-level XML preferences” on page 551. Sparse import If this feature is turned on during XML import, incoming elements that have no content (or only whitespace for content) do not replace content in the matching existing XML element in the XML template. By default, this feature is turned off. Architecture The feature is controlled by an XML-related preference (kXMLSparseImportOptionsServiceBoss). The top-level SAX handler (kSAXDocumentHandlerBoss) acts on this preference, rather than the service (kXMLSparseImportOptionsServiceBoss) being responsible for providing the behavior. This explains why kXMLSparseImportOptionsServiceBoss has no service interface: it is not implementing a particular extension pattern other than for XML import preferences. For details on how to turn sparse import on and off, see “Service-level XML preferences” on page 551. XML Fundamentals 523 XML Fundamentals Exporting XML Importing a CALS table as an InDesign table You can choose whether to import a CALS table as an InDesign table. You can use this feature when you have a table specified in CALS table format and you want to manipulate it the same way as InDesign native tables. Architecture This feature is implemented by a matchmaking service (kXMLTableMatchMakerServiceBoss) and DOM serializer handler service; see “XMl-import matchmaker” on page 555 and “SAX DOM serializer handler” on page 557. During the matchmaker phase, a special attribute, kTableFormatAttr (“tformat”), with value kAttrValueCALS (“CALS”), is inserted into the table element. During the DOM serializer phase, contents in the CALS table are altered to fit the InDesign table format. This feature can be turned on or off by a service-specific import preference (IXMLImportPreferences); see “Service-level XML preferences” on page 551. For more information on controlling the feature, see the “XML” chapter of Adobe InDesign CS4 Solutions. Support table and cell styles when importing an InDesign table You can specify table and cell styles when importing an InDesign table. A table-style attribute applies only to a table element. Cell-style attributes apply to either a table element or a cell element; they are ignored for other types of elements. If the style name specified in the attribute value does not exist, a new style with that name is created and then applied to the table or cell. Architecture This feature is implemented by a post-import responder (kXMLImporterPostImportMappingBoss), the same way as character style and paragraph style; see “Attribute-style mapping” on page 522. The only difference is that the attribute names are tablestyle and cellstyle. Exporting XML Exporting XML data from InDesign is considerably more straightforward than importing XML data into InDesign. The downside to this is that there are fewer opportunities for your plug-in to customize the export side. You can export the logical structure of an InDesign document as an XML document. The export takes place in document order, meaning the logical structures of the InDesign document and exported XML data are the same. An XML file can be exported from any element in the logical structure. For example, if exported from the root element, the exported XML data represents the logical structure of the entire document. If another element—for example, E—is chosen, the exported XML data represents the logical structure of the subtree with E at its root. Even an empty InDesign document has some (albeit trivial) logical structure: it has one root element with no dependents. If exported as XML data, one element (<Root></Root>) is writ- 524 XML Fundamentals Exporting XML ten to the output file. Figure 232 shows the logical structure of an new, empty document and the XML data exported from InDesign with the default settings. Note the default encoding (UTF-8). FIGURE 232 Structure of empty document and XML exported "[POYHUVLRQ HQFRGLQJ 87)VWDQGDORQH \HV"! Root></Root> There are two points to note about the relationship between XML data exported from InDesign and the logical structure: z XML content can be exported from a document even if it is not associated with placed content in the document. Exported XML data is based on the logical structure, irrespective of whether the elements are associated with content in the document. z The order in which the elements appear in the XML output is based on the logical structure and has no direct relation with the hierarchy of the native document model. The exception to this is a story with mark-up, in which case the order of the elements in the logical structure within the subtree corresponding to the story corresponds to the story-reading order. Export architecture An XML generator (IXMLGenerator) is an abstraction responsible for generating the XML content during export. The IXMLGenerator interface is aggregated by classes representing XML elements (IIDXMLElement) in the logical structure. The mechanism that supports XML export is a standard export provider (kXMLExportProviderBoss, IExportProvider). This delegates to an instance of kXMLExportHandlerBoss to perform the actual export. The implementation of IXMLHandler iterates elements in the logical structure, calling methods through the IXMLGenerator interface of the elements. This sequence diagram in Figure 233 shows some of the messages sent during a typical XML export. XML Fundamentals 525 XML Fundamentals Exporting XML FIGURE 233 export-provider XML-export sequence xmlUtils xmlAccess xmlHandler xmlGenerator IXMLUtils::ExportElement IXMLAccess::VisitAllElements IXMLHandler::HandleElementBefore IXMLGenerator::GenerateBeginTag IXMLHandler::HandleAfterNthChild IXMLGenerator::GenerateContent IXMLHandler::HandleElementAfter IXMLGenerator::GenerateEndTag The export provider (kXMLExportProviderBoss), shown as export-provider in Figure 233, starts the export. The parser service (kXMLParserServiceBoss) has an IXMLAccess interface, shown as the xmlAccess object. An instance of kXMLExportHandlerBoss, shown as xmlHandler, with signature interface IXMLHandler, iterates elements in the logical structure. The implementation of the IXMLGenerator interface on these elements generates XML content to the output stream. There are several implementations of this interface, generating different content types on export. Contributions to XML export come from instances of boss classes that expose the IXMLGenerator interface. These classes represent elements in the logical structure; e.g., kTextXMLElementBoss (tagged stories, tagged text ranges, and tagged graphics) and kXMLCommentBoss (XML comments). You can participate in the export process by providing a custom kXMLExportHandlerSignalService. The providers are called when the XML handler iterates elements. For more information, see the extension pattern in “XML-export handler” on page 558. Document order The logical structure of an InDesign document is exported as XML in document order, as defined in the XPath specification (http://www.w3.org/TR/xpath#dt-document-order). For convenience, part of the definition is repeated here: 526 XML Fundamentals Exporting XML “There is an ordering, document order, defined on all the nodes in the document corresponding to the order in which the first character of the XML representation of each node occurs in the XML representation of the document after expansion of general entities. Thus, the root node will be the first node. Element nodes occur before their children. Thus, document order orders element nodes in order of the occurrence of their start-tag in the XML (after expansion of entities). The attribute nodes and namespace nodes of an element occur before the children of the element. ... Reverse document order is the reverse of document order.” Document order has no direct relationship with the order in which a document would be read or other ordering schemes you might devise (e.g., based on page numbering). Tagged graphic placeholder, exported Consider the case, shown in Figure 234, of a simple but nontrivial logical structure in which a tagged placeholder is intended as the destination for an image. FIGURE 234 Tagged graphic placeholder Exporting the logical structure with default export options results in the XML data shown in Figure 235. To vary the options, like the encoding, see “XML-related preferences” on page 549. FIGURE 235 Exported XML from document with tagged-graphic placeholder <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> - <Root> <image /> </Root> The abstraction responsible for generating the XML data related to the tagged graphic is the element (IIDXMLElement) that represents the graphic. It exposes the IXMLGenerator interface, which is used during the export process. XML Fundamentals 527 XML Fundamentals Exporting XML Tagged text range, exported Consider the example in which you create a text frame, tag the story running through it with a tag named “story,” then tag a range within that story with a different tag named “emphasis.” The XML story element represents the instance of the tagged story. The XML emphasis element represents the tagged content item with value “Hello.” This is shown in Figure 236. The screenshot shows logical structure, tags, and layout view for a document with one text frame, with a tagged text range. The story is tagged “story” and represented by the story element in the logical structure. The text range is tagged “emphasis” and represented by the emphasis element. FIGURE 236 Tagged text range before export If you export the logical structure as XML data from the root element, you get the XML data shown in Figure 237. This time, the export option to export with UTF-16 encoding is set, to make it easier to inspect the Unicode character that represents the hard carriage return in the story. This XML data was exported by InDesign from the document shown in Figure 236. FIGURE 237 XML exported for tagged text range <?xml version="1.0" encoding="UTF-16" standalone="yes" ?> - <Root> - <story> <emphasis>Hello</emphasis> world </story> </Root> The XML content of the exported story requires some study. The intent of the InDesign function is that stories should be represented in exported XML data as closely as possible to how InDesign represents them internally. The end-of-line character corresponding to the hard car- 528 XML Fundamentals Tags riage return after the word “world” is represented by the Unicode character 0x2029. If you open the XML file in a binary editor on Windows—which is little-endian—the Unicode character 0x2029 is represented as the octet 29 and then the octet 20. Soft carriage returns are represented by 0x2028. See IXMLOutStream. This is shown in Figure 238; the 0x2029 (hard carriage return) is highlighted. FIGURE 238 Story exported from InDesign as XML in UTF-16 encoding Tags Tags can be loaded from several different sources, including the following: z An InDesign tag file, an XML document containing only tag-specific information. z Any XML document that is an instance of the document type being worked with. z By associating a DTD with the document. Doing this means the DTD is parsed for element tag names, and tags are created correspondingly. Elements defined within entities are ignored. Example 38 is a sample tag list. EXAMPLE 38 Sample tag list <?xml version="1.0" encoding="UTF-16" standalone="yes"?> <article colorindex="4"> <articleinfo colorindex="6"/> ... (other elements omitted) <ulink colorindex="19"/> </article> It also is possible to specify the color of the tag using RGB coordinates, which are used for any tags defined with a custom color. The coordinates are hex-encoded; for example, one tag with a custom color (0,0,255) in decimal RGB coordinates appears below: <link rgb="0 0,0 0,3ff00000 0"/> In addition, the custom-tag service-extension pattern lets you customize what tags are created when an XML document is being parsed. See “Custom-tag service” on page 557. XML Fundamentals 529 XML Fundamentals Tags Architecture The kXMLTagBoss boss class represents an individual entry in a tag list. The signature interface of this boss class is IXMLTag; this stores properties like the name and color in the user interface. The tag list is represented by IXMLTagList. IXMLTagList is aggregated on the session workspace (kWorkspaceBoss), representing a default set of tags for any new document. IXMLTagList is aggregated on the document workspace (kDocWorkspaceBoss), representing tags in a given document. The session workspace (kWorkspaceBoss) stores zero or more tags. A document workspace (kDocWorkspaceBoss) stores one or more tags; the minimal tag set for a new document consists of the Root tag. Tagging relationships are represented by associations between classes representing elements in the logical structure and those representing tags. For example, if a graphic frame is tagged for use as a placeholder, an association is created between the placeholder boss object (an instance of the kPlaceHolderItemBoss class) and an instance of the kTextXMLElementBoss class. An association is created between an element in the logical structure (IIDXMLElement) and an instance of kXMLTagBoss, to represent the tagging. Tags (kXMLTagBoss) that can be used to mark up content items in the native document model are held in the tag list (IXMLTagList) of a workspace (kDocWorkspaceBoss, kWorkspaceBoss). Tags are rendered in the Tags panel (Figure 218) and shown in views like layout view (Figure 216) or story view (Figure 217). XML elements that have tag names are associated with tags (kXMLTagBoss) that store the tag names. Given a reference to an XML element, you can find the tag string through a method on IIDXMLElement. You also can use IIDXMLElement::GetTagUID to acquire a reference to an instance of kXMLTagBoss representing the tag. You can acquire a reference to a tag (kXMLTagBoss) in a document through the tag list (IXMLTagList) on the document workspace (kDocWorkspaceBoss). The tagUIDRef variable refers to an instance of kXMLTagBoss. The class diagram in Figure 239 shows associations between tags and workspaces and the document (kDocBoss). 530 XML Fundamentals Tags FIGURE 239 Tags «boss» kDocBoss 1 IDocument::GetDocWorkspace 1 «boss» kWorkspaceBoss «boss» kDocWorkspaceBoss 1 1 IXMLTagList::GetTag «boss» kXMLTagBoss 1..* IXMLTagList::GetTag 0..* Tag-to-style mapping Suppose you have XML content with a headline tag and a p-head-1 paragraph style in your XML template. You can create an association between tags and styles in the document, to enable incoming XML to be styled automatically. When a tag-to-style mapping is applied during the XML import, inbound XML content has the styles applied when elements with tag names matching the tags in the tag-to-style map are encountered. For example, if you create a mapping from the headline tag to the p-head-1 paragraph style, textual content in a headline element has the p-head-1 style applied. The user interface for this feature is shown in Figure 219. This establishes a one-to-one mapping from tag names to character or paragraph styles, which is sufficient when context-sensitive styling is not required. If context-sensitive styling for incoming XML is required, you can use a combination of a stream-based XML transformer and attribute-style mapping to achieve this. See “XML transformer” on page 554 and “Attribute-style mapping” on page 522. Architecture Figure 240 is a class diagram for tag-to-style mappings (IXMLTagToStyleMap). The session workspace (kWorkspaceBoss) stores the default mapping inherited by new documents. The document workspace (kDocWorkspaceBoss) stores the mapping applied to a particular document (kDocBoss). XML Fundamentals 531 XML Fundamentals Tags FIGURE 240 Tag-to-style mapping IXMLTagToStyleMap::GetStyleMappedToTag «boss» kStyleBoss 0..* IXMLTagToStyleMap::GetStyleMappedToTag 0..* 1 1 «boss» kWorkspaceBoss «boss» kDocWorkspaceBoss 1 1 0..* IXMLTagToStyleMap::GetTagAt «boss» kXMLTagBoss IXMLTagToStyleMap::GetTagAt 0..* Style-to-tag mapping Figure 241 is a screenshot of an unstructured but systematically styled document, which as an associated DTD. Figure 242 shows the result of applying a style-to-tag mapping. 532 FIGURE 241 Before mapping styles to tags FIGURE 242 After mapping styles to tags XML Fundamentals Tags Once a style-to-tag mapping is defined and applied, ranges of styled text with the styles mapped to given tags end up tagged, creating new elements in the logical structure. There are some default commitments in terms of the tags applied; for example, the Story tag is used for a story, even if it is not in the tag list of the document when the style-to-tag mapping is applied. Architecture The class diagram in Figure 243 shows the associations between workspaces (IWorkspace), tags (kXMLTagBoss), and styles (kStyleBoss), mediated by the style-to-tag map (IXMLStyleToTagMap). The session workspace (kWorkspaceBoss) stores the default style-to-tag map for new documents. The document workspace (kDocWorkspaceBoss) stores the style-to-tag map for a given document (kDocBoss). FIGURE 243 Style-to-tag mapping 0..* IXMLStyleToTagMap::GetStyleAt «boss» kStyleBoss IXMLStyleToTagMap::GetStyleAt 0..* 1 1 «boss» kWorkspaceBoss «boss» kDocWorkspaceBoss 1 1 IXMLStyleToTagMap::GetTagMappedToStyle 0..* «boss» kXMLTagBoss IXMLStyleToTagMap::GetTagMappedToStyle 0..* Text styles are represented by kStyleBoss. Collections of styles are held in the style-name table (IStyleNameTable) and stored in a workspace (IWorkspace). The session workspace (kWorkspaceBoss) stores text styles that are defaults for new documents. The document workspace (kDocWorkspaceBoss) stores text styles that can be used in the associated document. For more information on text styles, see the “Text Fundamentals” chapter and the API reference documentation for kStyleBoss. The workspace (IWorkspace) maintains an associative map between text styles (kStyleBoss) and tags (kXMLTagBoss). This map is stored in the persistent interface IXMLStyleToTagMap. The workspace style list (IStyleNameTable) may contain styles that are not referenced in the style-to-tag map. Similarly, there may be tags in the tag list (IXMLTagList) of the workspace that are not involved in the style-to-tag map. XML Fundamentals 533 XML Fundamentals Elements and content Elements and content Tagged graphic placeholder Suppose you are building an XML template and you want to create placeholders into which images will be placed when an XML data file is imported. To create a placeholder graphic for an image, follow these steps: 1. Create a new document. 1. Create a tag named “image” through the Tags panel (Window > Tags). 2. Create a rectangle page item with the Rectangle tool. 3. Leave the page item selected, and click on the image tag in the Tags panel. 4. Show the structure view. It should look like Figure 244. Architecture The UML object diagram in Figure 244 shows the boss objects representing a tagged graphic placeholder and some of the relationships between them. The placeholder object (kPlaceHolderItemBoss) is a child of a graphic frame (kSplineItemBoss); the latter is omitted from this diagram, in the interest of simplicity. Content items like kPlaceHolderItemBoss have an IXMLReferenceData interface, which lets them refer to an element in
advertisement